我使用下面的代码来启动带有list参数的线程,但有时会引发异常:
字典中没有给定的密钥
从这一行:
Thread MoveThread = new Thread(() => MoveTask(ControllerDictionary[i]));
如何修复该错误?
完整代码:
var ControllerDictionary = ConfigFile.ControllerList.Select((c, i) => new { Controller = c, Index = i })
.GroupBy(x => x.Index % AppSettings.SimultaneousProcessNumber)
.Select((g, i) => new { GroupIndex = i, Group = g })
.ToDictionary(x => x.GroupIndex, x => x.Group.Select(xx => xx.Controller).ToList());
for (int i = 0; i < ControllerDictionary.Count; i++)
{
Thread MoveThread = new Thread(() => MoveTask(ControllerDictionary[i]));
MoveThread.Start();
foreach (var Controller in ControllerDictionary[i])
Logger.Write(string.Format("{0} is in move thread {1}.", Controller.Ip, (i + 1)),EventLogEntryType.Information, AppSettings.LogInfoMessages);
}
答案 0 :(得分:8)
您正在捕获变量 i
,而不是其值。因此,目前您可以使用相同的索引调用MoveTask
多个线程...有时i
的值可能等于ControllerDictionary.Count
。
如果你将i
的副本带入循环中的变量,那就解决了问题,因为你将在循环的每次迭代中得到一个单独的变量:
for (int i = 0; i < ControllerDictionary.Count; i++)
{
int index = i;
Thread MoveThread = new Thread(() => MoveTask(ControllerDictionary[index]));
...
}
甚至更好,完全从线程中提取ControllerDictionary
提取:
for (int i = 0; i < ControllerDictionary.Count; i++)
{
var value = ControllerDictionary[i];
Thread MoveThread = new Thread(() => MoveTask(value));
...
}
此外,为什么你要使用字典并不是很清楚。鉴于您知道密钥将全部在[0, count)
范围内,为什么不使用数组?您将查询更改为:
var controllerLists = ConfigFile.ControllerList
.Select((c, i) => new { Controller = c, Index = i })
.GroupBy(x => x.Index % AppSettings.SimultaneousProcessNumber)
.Select(g => g.Select(xx => xx.Controller).ToList())
.ToArray();
答案 1 :(得分:2)
问题在于:
Thread MoveThread = new Thread(() => MoveTask(ControllerDictionary[i]));
该匿名函数将在另一个线程上执行,并且无法保证局部变量有效。