我有以下测试:

using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading.Tasks;               

public class Program
{
    public static void Main()
    {
        IDictionary<string, string> dictionary = new ConcurrentDictionary<string, string>(); // FAILS sometimes
        // ConcurrentDictionary<string, string> dictionary = new ConcurrentDictionary<string, string>(); // WORKS always

        Parallel.For(0, 10, i => dictionary.TryAdd("x1", "y1"));
    }
}

如果我在.NET FIDELL中运行它,有时会得到以下异常:

Unhandled exception. System.AggregateException: One or more errors occurred. (The key already existed in the dictionary)
System.ArgumentException: The key already existed in the dictionary.

at System.Collections.Concurrent.ConcurrentDictionary`2.System.Collections.Generic.IDictionary<TKey,TValue>.Add(TKey key, TValue value)
at System.Collections.Generic.CollectionExtensions.TryAdd[TKey,TValue](IDictionary`2 dictionary, TKey key, TValue value)
at Program.<>c__DisplayClass0_0.b__0(Int32 i)
at System.Threading.Tasks.Parallel.<>c__DisplayClass19_0`2.b__1(RangeWorker& currentWorker, Int64 timeout, Boolean& replicationDelegateYieldedBeforeCompletion)
--- End of stack trace from previous location ---
at System.Threading.Tasks.Parallel.<>c__DisplayClass19_0`2.b__1(RangeWorker& currentWorker, Int64 timeout, Boolean& replicationDelegateYieldedBeforeCompletion)
at System.Threading.Tasks.TaskReplicator.Replica.Execute()
--- End of inner exception stack trace ---

然而,如果我不施展ConcurrentDictionary,它似乎总是有效的.

到底怎么回事?

推荐答案

这一点实际上在"线程安全"部分的ConcurrentDictionary<TKey,TValue>个文档中涵盖了,它隐藏在如此遥远的地方,几乎每个人都忽略了它(强调我的):

Thread Safety

ConcurrentDictionary<TKey,TValue>的所有公共成员和受保护成员都是线程安全的,并且可以从多个线程并发使用.一百零二

IDictionary<string, string> dictionary = ..属于扩展方法类别,具体地说是CollectionExtensions.TryAdd<TKey,TValue>(IDictionary<TKey,TValue> dictionary, ...)

因此,简而言之,如果您需要以线程安全的方式使用字典,请不要通过接口/扩展方法使用它,而要使用Remarks小节中列出的方法:

所有这些操作都是原子的,对于ConcurrentDictionary<TKey,TValue>类上的所有其他操作来说都是线程安全的……

Csharp相关问答推荐

[0-n]范围内有多少个Integer在其小数表示中至少包含一个9?

如何从C#中有类.x和类.y的类列表中映射List(字符串x,字符串y)?

Serilog SQL服务器接收器使用UTC作为时间戳

如何创建ASP.NET Core主机并在同一进程中运行请求

ITypeLib2.GetLibStatistics()在C#中总是抛出AccessViolationException

可为空的泛型属性

从Blob存储中提取tar.gz文件并将提取结果上载到另一个Blob存储

将现有字段映射到EFCore中的复杂类型

在路由中使用枚举

应用程序重新启动后,EFCore列表的BSON反序列化错误

C#阻塞调用或await calling inside calling方法

TeamsBot SendActivityActivityTypes与ActivityTypes同步.键入不再起作用

如何在C#中创建VS代码中的控制台应用程序时自动生成Main方法

JsonSchema.Net删除假阳性判断结果

我什么时候应该在Dapper中使用Connection.OpenAsync?

如何避免在.NET中将日志(log)写入相对路径

在.NET8中如何反序列化为私有字段?

Xamarin.Forms中具有类似AspectFill的图像zoom 的水平滚动视图

在使用.NET EF Core DbContext属性之前,是否应使用null判断

如何对正方形格线进行对角分组