1

我正在使用下面的代码以列表参数启动线程,但有时它会引发异常:

字典中不存在给定的键

从这一行:

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);
}
4

2 回答 2

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完全从线程中提取 fetch:

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();
于 2013-05-20T07:41:38.627 回答
2

问题在这里:

Thread MoveThread = new Thread(() => MoveTask(ControllerDictionary[i]));

该匿名函数将在不同的线程上执行,并且不能保证局部变量将有效。

于 2013-05-20T07:44:09.330 回答