我有一个static
类,比如说A
类,它有这个函数AddMaster
:
public static void AddMaster(string ipAddress, int port, List<RegisterMap> registers)
{
// THIS LINE PRINTS THE ACTUAL VALUES SENT FROM THE CALLER FUNCTION
System.IO.File.AppendAllText("datalog_MB.txt", ipAddress + " " + registers[0].FriendlyName + "n");
new Thread(() =>
{
_tasks.Add(Task.Factory.StartNew(() =>
{
Monitor.Enter(_masters);
_masters.Add(new Master().Connect(ipAddress, port).SetRegisters(registers));
_masters.Last().OnEvent += MasterEvent;
Debug.WriteLine(_masters.Count + " TCP masters connected");
Monitor.Exit(_masters);
}));
}).Start();
}
我有另一个non-static
类Master
,具有函数SetRegisters
:
public Master SetRegisters(List<RegisterMap> registerList)
{
// HERE THE FriendlyName ALWAYS PRINTS THE VALUE OF THE LAST FUNCTION CALL
System.IO.File.AppendAllText("datalog_MB_1.txt", _hostname + " " + registerList[0].FriendlyName + "n");
_registersToRead = registerList;
return this;
}
函数AddMaster()
在循环中被调用。
第一个代码记录以下内容,这是正确的:
# datalog_MB.txt
192.168.0.12 192.168.0.12:Value 1
192.168.0.11 192.168.0.11:Value 1
但是,第二个代码块打印以下内容(请参阅第二个值已更改):
# datalog_MB_1.txt
192.168.0.12 192.168.0.11:Value 1
192.168.0.11 192.168.0.11:Value 1
编辑#1
foreach (var equipment in MSSQL.GetEquipments(true))
{
registers.Clear();
System.IO.File.AppendAllText("dataeq.txt", equipment.IPAddress + " " + equipment.Name + " " + equipment.ID + "n");
try
{
registers.Add(
new RegisterMap
{
FriendlyName = equipment.IPAddress + ":Value 1",
Register = 2001,
Type = RegisterType.HoldingRegister,
StationID = 1
});
registers.Add(
new RegisterMap
{
FriendlyName = equipment.IPAddress + ":Value 2",
Register = 2002,
Type = RegisterType.HoldingRegister,
StationID = 1
});
A.AddMaster(equipment.IPAddress, 502, registers);
var json = new JavaScriptSerializer().Serialize(registers);
System.IO.File.AppendAllText("data_reg.txt", json + "nn");
}
catch(Exception err)
{
System.Windows.MessageBox.Show(err.Message);
}
}
编辑#2*
Fiddle:https://dotnetfiddle.net/h3yn7p
知道可能出了什么问题吗?
您不应该Clear
registers
-重新创建它:
List<RegisterMap> registers = null;
foreach(var equipment in equipments)
{
registers = new List<RegisterMap>();
....
}
否则,您将在多个线程中并行处理List<RegisterMap>
的同一实例,同时对其进行操作(即,具有foreach(var equipment in equipments)
循环的线程将运行并创建所有线程并启动它们),这可能会导致许多不同的并发问题。
还有一些注意事项:
- 考虑使用并发集合,例如
ConcurrentBag<T>
而不是Monitor
+List
(因为在当前代码中,它使Thread
/Task
处理毫无意义) - 根据提供的代码,不需要创建
Thread
——任务就足够了。在现代.NET中,很少有需要手动创建Thread
的情况,大多数时候都非常不鼓励(阅读更多)