c# - 此线程使用此 ConcurrentDictionary 和 AddOrUpdate 方法是否安全?

标签 c# thread-safety concurrentdictionary

我对 C# 中的并发字典有疑问。

在另一个问题中,有人问我如何拥有一个以哈希集作为值的并发字典,但使用哈希集并不是一个好主意,最好使用并发字典作为值。所以我得到的解决方案是这样的:

var myDic = new ConcurrentDictionary<long, ConcurrentDictionary<int, byte>>();
myDic.AddOrUpdate(key, 
    _ => new ConcurrentDictionary<int, byte>(new[] {new KeyValuePair<int, byte>(element, 0)}),
    (_, oldValue) => {
        oldValue.TryAdd(element, 0);
        return oldValue;
    });

假设我有两个线程,其中“元素”在线程 A 中为 1,在线程 B 中为 2。

我怀疑这是否是线程安全的。我可能是错的,但我认为并发字典是这样工作的:

线程A:尝试为key 1插入元素1。key 1不存在,所以它尝试用并发字典ConcurrentDictionary<int, byte>(new[] {new KeyValuePair<int, byte>(1, 0)插入key 1 .

线程B:尝试向键1的字典中插入item 2,线程A还在添加新的键/值,线程B认为键1不存在,所以尝试添加值ConcurrentDictionary<int, byte>(new[] {new KeyValuePair<int, byte>(2, 0)到关键 1。

线程A成功插入键/值对。

线程 B 试图完成,但现在键 1 存在,因为线程 A 插入了键 1。因此线程 B 无法插入键/值。

然后呢?线程 B 的工作被丢弃,所以我在并发字典中只有一项用于键 1?或者线程 B 可能进入 updateValueFactory并将项目 2 添加到字典中?

最佳答案

AddOrUpdate 专为处理您描述的场景而设计;如果它不能优雅地处理它,它就没有用了。

当线程 B 尝试添加其计算值时,它将失败,因为该键已经存在。然后它将自动重试,此时它将执行更新而不是添加。具体来说,它将更新线程 A 产生的值。这是一种乐观并发的形式:算法假定它会成功,因此它会针对该结果进行优化,但它有一个回退计划以防万一失败。

但是请注意,此方法的乐观并发性质意味着您的 addValueFactoryupdateValueFactory 可能两者 都被调用;严格来说,这不是其中之一。在您假设的场景中,线程 B 将首先调用 addValueFactory,并且由于添加失败,稍后调用 updateValueFactory。在竞速更新的情况下,updateValueFactory 可能会在更新最终成功之前调用多次。

关于c# - 此线程使用此 ConcurrentDictionary 和 AddOrUpdate 方法是否安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48670104/

相关文章:

c# - Swagger 在 ASP.CORE 3 中为字典生成不正确的 URL

c# - 在 C# 应用程序中导入 scikit

c# - 在独占线程约束下锁定

multithreading - TCriticalSection 有很多读者和一个作者

c# - 如何实现以 ConcurrentDictionary 为条件的 TryRemove?

c# - Microsoft AVRO 是否能够序列化 ConcurrentDictionary?

c# - 关于使用 ConcurrentDictionary 的一些问题

c# - 具有模型导入功能的免费 opc ua 服务器

c# - 为构造函数类指定固定值和容器中的其他变量

java同步方法中的线程安全错误