c# - 变量未更新
问题描述
问题:
List<>
即使列表中没有可访问的数据,变量也正在通过引用检查。
解决方案:
Save() 函数在保存线程完成导致线程中止之前完成执行。threadrunning = true
在启动线程之前添加。
代码:
Thread saveThread;
public string filepath;
public string rootElementName;
public string objectElementName;
public int objectsSaved;
public SaveData saveData;
public List<SavedObject> datasets;
public bool threadRunning = false;
public bool syncingData = false;
public void StartSaveThread()
{
bool warned = false;
//The "error" is here
//The reference returns true but none of the data is accessible, there is nothing in the list
while(datasets != saveData.objects)
{
if(warned == false)
{
Debug.Log("Waiting for data to sync");
syncingData = true;
warned = true;
}
}
syncingData = false;
saveThread = new Thread(SaveData);
saveThread.Start();
}
public void SaveData()
{
bool saveComplete = false;
threadRunning = true;
while (threadRunning && saveComplete == false)
{
objectsSaved = 0;
XmlDocument saveFile = new XmlDocument();
XmlElement documentRoot = saveFile.CreateElement(rootElementName);
foreach (SavedObject dataset in datasets)
{
XmlElement savedObjectElement = saveFile.CreateElement(objectElementName);
foreach (SavedElement savedValue in dataset.data.savedElements)
{
XmlElement newElement = saveFile.CreateElement(savedValue.name);
newElement.InnerText = savedValue.value;
savedObjectElement.AppendChild(newElement);
}
documentRoot.AppendChild(savedObjectElement);
objectsSaved++;
}
saveFile.AppendChild(documentRoot);
saveFile.Save(filepath);
saveComplete = true;
}
threadRunning = false;
}
如果您想重现错误,可以在下面找到更多代码。
SavedObject 类(简化):
//this class is in SavedObject.cs
public int id = 0;
public string name = "";
public string objectPath = "";
public bool saveData;
public bool loadData;
public bool savePosition;
public bool saveRotation;
public bool saveScale;
public SavedObjectData data = new SavedObjectData();
public GameObject parent;
public List<SavedElement> savedElements = new List<SavedElement>();
public void StoreData()
{
data.id = id;
data.name = name;
data.objectPath = objectPath;
data.saveData = saveData;
data.loadData = loadData;
data.savePosition = savePosition;
data.saveRotation = saveRotation;
data.saveScale = saveScale;
Vector3 position = transform.position;
data.position = position;
Vector3 rotation = transform.rotation.eulerAngles;
data.rotation = rotation;
Vector3 scale = transform.localScale;
data.scale = scale;
}
public void LoadData()
{
id = data.id;
name = data.name;
objectPath = data.objectPath;
saveData = data.saveData;
loadData = data.loadData;
savePosition = data.savePosition;
saveRotation = data.saveRotation;
saveScale = data.saveScale;
if (savePosition) { transform.position = data.position; }
if (saveRotation) { transform.eulerAngles = data.rotation; }
if (saveScale) { transform.localScale = data.scale; }
savedElements = data.savedElements;
}
SavedObjectData 类(简化):
//this class is in SavedObject.cs
public int id;
public string name;
public string objectPath;
public bool saveData;
public bool loadData;
public bool savePosition;
public bool saveRotation;
public bool saveScale;
public Vector3 position;
public Vector3 rotation;
public Vector3 scale;
public List<SavedElement> savedElements = new List<SavedElement>();
public string BoolToString(bool value)
{
string result = "";
if (value)
{
result = "t";
}
else
{
result = "f";
}
return result;
}
public bool StringToBool(string value)
{
bool result;
if (value == "t")
{
result = true;
}
else
{
result = false;
}
return result;
}
public void StoreValues()
{
savedElements = new List<SavedElement>();
savedElements.Add(new SavedElement() { name = "ID", value = id.ToString() });
savedElements.Add(new SavedElement() { name = "Name", value = name });
savedElements.Add(new SavedElement() { name = "Path", value = objectPath });
savedElements.Add(new SavedElement() { name = "SD", value = BoolToString(saveData) });
savedElements.Add(new SavedElement() { name = "LD", value = BoolToString(loadData) });
savedElements.Add(new SavedElement() { name = "SP", value = BoolToString(savePosition) });
savedElements.Add(new SavedElement() { name = "SR", value = BoolToString(saveRotation) });
savedElements.Add(new SavedElement() { name = "SS", value = BoolToString(saveScale) });
if (savePosition) { savedElements.Add(new SavedElement() { name = "P", value = "x:" + position.x + "|y:" + position.y + "|z:" + position.z }); }
if (saveRotation) { savedElements.Add(new SavedElement() { name = "R", value = "x:" + rotation.x + "|y:" + rotation.y + "|z:" + rotation.z }); }
if (saveScale) { savedElements.Add(new SavedElement() { name = "S", value = "x:" + scale.x + "|y:" + scale.y + "|z:" + scale.z }); }
}
public void LoadValues()
{
foreach (SavedElement savedElement in savedElements)
{
string[] sectionedData;
switch (savedElement.name)
{
default:
break;
case "ID":
id = int.Parse(savedElement.value);
break;
case "Name":
name = savedElement.value;
break;
case "Path":
objectPath = savedElement.value;
break;
case "SD":
saveData = StringToBool(savedElement.value);
break;
case "LD":
loadData = StringToBool(savedElement.value);
break;
case "SP":
savePosition = StringToBool(savedElement.value);
break;
case "SR":
saveRotation = StringToBool(savedElement.value);
break;
case "SS":
saveScale = StringToBool(savedElement.value);
break;
case "P":
sectionedData = savedElement.value.Split('|');
position = new Vector3(float.Parse(sectionedData[0].Split(':')[1]), float.Parse(sectionedData[1].Split(':')[1]), float.Parse(sectionedData[2].Split(':')[1]));
break;
case "R":
sectionedData = savedElement.value.Split('|');
rotation = new Vector3(float.Parse(sectionedData[0].Split(':')[1]), float.Parse(sectionedData[1].Split(':')[1]), float.Parse(sectionedData[2].Split(':')[1]));
break;
case "S":
sectionedData = savedElement.value.Split('|');
scale = new Vector3(float.Parse(sectionedData[0].Split(':')[1]), float.Parse(sectionedData[1].Split(':')[1]), float.Parse(sectionedData[2].Split(':')[1]));
break;
}
}
}
SavedElement 类(简化):
//this class is in SavedObject.cs
public string name;
public string value;
SaveData 类(简化):
//this class is in SaveData.cs
private IEnumerator SaveObjects(string path, string rootElementName, string objectElementName, GameObject savedObjects){
objects = new List<SavedObject>();
//Compiles List
foreach (Transform savedObject in savedObjects.transform)
{
if(savedObject.gameObject.GetComponent<SavedObject>() != null)
{
objects.add(savedObject.gameObject.GetComponent<SavedObject>())
}
}
//Creates new instance of SaveSystem
saveSystem = new SaveSystem
{
filepath = path,
rootElementName = rootElementName,
objectElementName = objectElementName,
saveData = this,
datasets = objects
};
//checks if saveSystem.datasets == objects then starts the thread to save the data
//PLEASE NOTE: the reference is true but none of the data is updated and accessible
saveSystem.StartSaveThread();
while (saveSystem.threadRunning || saveSystem.syncingData)
{
yield return null;
}
}
SaveSystem 类(简化):
//this class is in SaveSystem.cs
public SaveData saveData;
public string filepath;
public string rootElementName;
public string objectElementName;
public int objectsSaved;
public List<SavedObject> datasets;
Thread saveThread;
public volatile bool threadRunning = false;
public volatile bool syncingData = false;
public void SaveData()
{
bool saveComplete = false;
threadRunning = true;
while (threadRunning && saveComplete == false)
{
objectsSaved = 0;
XmlDocument saveFile = new XmlDocument();
XmlElement documentRoot = saveFile.CreateElement(rootElementName);
foreach (SavedObject dataset in datasets)
{
XmlElement savedObjectElement = saveFile.CreateElement(objectElementName);
foreach (SavedElement savedValue in dataset.data.savedElements)
{
XmlElement newElement = saveFile.CreateElement(savedValue.name);
newElement.InnerText = savedValue.value;
savedObjectElement.AppendChild(newElement);
}
documentRoot.AppendChild(savedObjectElement);
objectsSaved++;
}
saveFile.AppendChild(documentRoot);
saveFile.Save(filepath);
saveComplete = true;
}
threadRunning = false;
}
public void StartSaveThread()
{
bool warned = false;
//The error is here
//The reference returns true but none of the data is accessible
while(datasets != saveData.objects)
{
if(warned == false)
{
Debug.Log("Waiting for data to sync");
syncingData = true;
warned = true;
}
}
syncingData = false;
saveThread = new Thread(SaveData);
saveThread.Start();
}
解决方案
我首先让它易于重现,例如,启动线程,等待一秒钟,然后分配 List 变量,以便您可以通过让线程首先运行来不断重现竞争条件。
也许更改您的逻辑,以便在您确定已设置变量之前不要启动线程,或者您可以使用https://msdn.microsoft.com/en-us/library/system.threading。线程调用 WaitOne() 的manualresetevent(v=vs.110).aspx对象,这将阻塞该行上的线程,直到您的 List 代码路径分配该值,然后在 ManualResetEvent 上调用 Set() 事件。
推荐阅读
- linux - 如何从在 Linux 上运行的 .NET Core 应用程序对 Windows 域用户进行身份验证
- python - 如何成功编译 python 3.x
- sql - 在删除语句postgresql中使用partition by子句
- python - 如果满足条件,则获取列表列表的最大元素
- automated-tests - 仅在一次测试中禁用赛普拉斯中的网络安全
- wiremock - 我可以将 Spring Cloud Contract 定义为代理,并且只为端点子集制作存根吗?
- c++ - '--p' 如何在 for(p=&(*L).elem[(*L).length-1];p>=q;--p) 中工作?
- c++ - 我应该在 ECS 中使用静态类吗?
- python - 计算每个 bin 中的值数:Python
- java - 如何在 Java 中删除新行