Threading Dictionary <string,int>和locks

时间:2015-08-05 20:23:23

标签: c# multithreading

我有一个字典在两个线程中使用,一个是发送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后才得到错误,在第二次迭代中它出错:

该集合已更改。枚举操作可能无法执行(从荷兰语翻译)

我该如何解决这个问题?显然,在这种情况下,字典对我来说最容易使用。

4 个答案:

答案 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--)
{
}