我有一个字典在两个线程中使用,一个是发送UDP数据包,一个是接收它们。两者都保持一个共同的集合,看看计数传出和返回数据包,并希望保持它们0差异:)
现在我正在迭代字典来更新值,迭代后它出错了。我确实有一个锁定对象,我怎么能解决这个问题呢?
第一线程:
lock (retryListLock)
{
// loop through all known devices in the device list to build a counter if the device still lives
foreach(string key in retryList.Keys)
{
retryList[key] += 1;
if (retryList[key] > Retries)
{
DiscoveredDevice device = Devices.Find(d => d.SerialNo == key);
if (device != null)
{
OnDeviceRemoved(device);
Devices.Remove(device);
retryList.Remove(key);
}
}
}
}
第二线程:
lock (retryListLock)
{
if (retryList.ContainsKey(frame.SerialNo))
retryList[frame.SerialNo] = 0;
else
retryList.Add(frame.SerialNo, 0);
}
我只是在第一个线程为该项的值添加+1后才得到错误,在第二次迭代中它出错:
该集合已更改。枚举操作可能无法执行(从荷兰语翻译)
我该如何解决这个问题?显然,在这种情况下,字典对我来说最容易使用。
答案 0 :(得分:1)
问题是您无法在迭代器/ foreach中更改字典
foreach(string key in retryList.Keys)
{
retryList[key] += 1; // <-- The error happens here ! Do not alter the Dictionary during an iteration
if (retryList[key] > Retries)
{
DiscoveredDevice device = Devices.Find(d => d.SerialNo == key);
if (device != null)
{
OnDeviceRemoved(device);
Devices.Remove(device);
retryList.Remove(key); // <-- The error could also happen here ! Do not alter the Dictionary during an iteration
}
}
}
我在stackoverflow上发现了这个问题,这可能会对你有所帮助
How to iterate through Dictionary and change values?
我们在这里找到MSDN
的声明foreach语句是枚举器的包装器,允许使用 只读取集合,而不是写入它。
答案 1 :(得分:1)
感谢Bongo,将密钥带入第二个迭代列表解决了它:
List<string> Keys = new List<string>(retryList.Keys);
foreach(string key in Keys)
答案 2 :(得分:0)
错误与锁和多线程无关。 当您修改枚举器在循环中枚举的相同数据结构(字典)时,您的枚举器(foreach正在使用的)无效。
解决方案:
你必须首先使用foreach循环说明,并且记住几乎在列表中应删除的内容。然后在记住的键的单独循环中,将它们从字典中删除。
答案 3 :(得分:0)
这可能对您有用。 Concurrent Dictionary 它是线程安全的
同时将for each更改为reverse for loop 像这样的东西。
for (int x = max; x>=1; x--)
{
}