ConcurrentDictionary Keys 或 Values 属性是线程安全的 [英] Is ConcurrentDictionary Keys or Values property threadsafe

查看:46
本文介绍了ConcurrentDictionary Keys 或 Values 属性是线程安全的的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

ConcurrentDictionary 的线程安全有疑问.从 API 中,我看到枚举器是线程安全的,但对于键和值属性,我没有看到相同的内容.我的问题是:

Have a question regarding thread safety with ConcurrentDictionary. From the API, I see that the enumerator is thread-safe, but I don't see the same for keys and values properties. My question is:

当有其他线程同时修改 KeysValues 集合时,它是否安全?

Is it safe to loop over the Keys or Values collection when there are other threads modifying it concurrently?

推荐答案

虽然我喜欢文档,但我倾向于在有疑问或我觉得我可能假设太多时用一个小程序来验证事情.

While I do like the documentation, I tend to verify things with a small program when in doubt or I feel that I might be assuming too much.

以下代码验证您确实可以安全地枚举值集合,同时从单独的线程向正在枚举的线程添加或删除键.这不会导致通常的集合被修改异常.更详细地说,这里有几个测试用例

The following code verifies that indeed you can enumerate the values collection safely while adding or removing keys from a separate thread to that on which the enumeration is taking place. This will not cause the usual collection was modified exceptions. In more detail, here are a couple of test cases

案例 1:枚举值并删除一个键

如果您遵循以下顺序:

  • 从线程开始枚举值集合
  • 从我们尚未枚举的其他线程中删除一个键
  • 在原线程上继续枚举

观察到的行为是删除的键确实会被枚举,因为它在我们开始枚举时存在于值集合中.不会引发任何异常.

The observed behavior is that the removed key will indeed be enumerated since it existed in the values collection when we started the enumeration. No exception will be raised.

案例 2:枚举值并添加键

  • 从线程开始枚举值集合
  • 从我们尚未枚举的不同线程添加一个新密钥
  • 在原线程上继续枚举

观察到的行为是添加的键不会被枚举,因为当我们开始枚举它时,它不存在于值集合中.无论我们使用 TryAdd 还是通过直接分配给字典(即 dictionary[key] = value)来添加都不会引发异常.

The observed behavior is that the added key will not be enumerated since it did not exist in values collection when we started to enumerate it. No exception will be raised whether we use TryAdd or add by assigning directly to the dictionary ie dictionary[key] = value.

示例代码

这是演示这两种情况的示例程序:

Here is the sample program that demonstrates both cases:

ConcurrentDictionary<int, int> dictionary = new ConcurrentDictionary<int, int>();

// Seed the dictionary with some arbitrary values; 
for (int i = 0; i < 30; i++)
{
    dictionary.TryAdd(i, i);
}

// Reader thread - Enumerate the Values collection
Task.Factory.StartNew(
        () =>
        {
            foreach (var item in dictionary.Values)
            {
                Console.WriteLine("Item {0}: count: {1}", item, dictionary.Count);
                Thread.Sleep(20);
            }

        }
);

// writer thread - Modify dictionary by adding new items and removing existing ones from the end
Task.Factory.StartNew(
        () =>
        {
            for (int i = 29; i >= 0; i--)
            {
                Thread.Sleep(10);
                //Remove an existing entry 
                int removedValue;
                if (dictionary.TryRemove(i, out removedValue))
                    Console.WriteLine("Removed item {0}", removedValue);
                else
                    Console.WriteLine("Did not remove item {0}", i);

                int iVal = 50 + i*2;
                dictionary[iVal] = iVal;
                Thread.Sleep(10);
                iVal++;
                dictionary.TryAdd(iVal, iVal);
            }
        }
);

Console.ReadKey();

这是发布模式下的输出:

这篇关于ConcurrentDictionary Keys 或 Values 属性是线程安全的的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆