在ConcurrentDictionary中更新列表

6 c# concurrency

所以我在ConcurrentDictionary中有一个IList作为值.

ConcurrentDictionary<int, IList<string>> list1 = new ConcurrentDictionary<int, IList<string>>;
Run Code Online (Sandbox Code Playgroud)

为了更新列表中的值,我这样做:

if (list1.ContainsKey[key])
{
  IList<string> templist;
  list1.TryGetValue(key, out templist);
  templist.Add("helloworld");
}
Run Code Online (Sandbox Code Playgroud)

但是,在templist中添加字符串是否更新ConcurrentDictionary?如果是,那么更新是否是线程安全的,以便不会发生数据损坏?

或者是否有更好的方法来更新或创建ConcurrentDictionary中的列表

编辑

如果我使用ConcurrentBag而不是List,我将如何实现它?更具体地说,我该如何更新它?ConcurrentDictionary的TryUpdate方法感觉有点过分.

ConcurrentBag.Add是否在线程安全的mannar中更新ConcurrentDictionary?

ConcurrentDictionary<int, ConcurrentBag<string>> list1 = new ConcurrentDictionary<int, ConcurrentBag<string>>
Run Code Online (Sandbox Code Playgroud)

Cod*_*ter 5

可以说,线程安全字典上的操作按键来说是线程安全的。因此,只要您IList<T>仅从一个线程访问您的值(在本例中为 ),就可以开始了。

ConcurrentDictionary 不会阻止两个线程同时访问属于一个键的值。

  • 我一瞬间没想到是你。我知道你总是解释反对票!:) (2认同)

Mat*_*son 5

首先,不需要执行ContainsKey() TryGetValue()

您应该这样做:

IList<string> templist;

if (list1.TryGetValue(key, out templist))
    templist.Add("helloworld");
Run Code Online (Sandbox Code Playgroud)

实际上,您编写的代码具有竞争条件。

在一个线程调用ContainsKey()TryGetValue()另一个线程之间可能已使用该键删除了该项目。然后TryGetValue()将返回tempListnull,然后在调用时会得到null引用异常tempList.Add()

其次,是的:这里还有另一个可能的线程问题。您不知道IList<string>字典中存储的内容是线程安全的。

因此tempList.Add(),不能保证通话安全。

您可以使用ConcurrentQueue<string>代替IList<string>。这可能将是最可靠的解决方案。

请注意,仅锁定访问权限IList<string>是不够的。

这不好:

if (list1.TryGetValue(key, out templist))
{
    lock (locker)
    {
        templist.Add("helloworld");
    }
}
Run Code Online (Sandbox Code Playgroud)

除非您在IList可能会访问的其他位置也使用相同的锁。这不容易实现,因此最好使用a ConcurrentQueue<>或向此类添加锁定并更改体系结构,以使其他任何线程都不能访问基础IList。


tym*_*167 5

您可以使用 ConcurrentDictionary.AddOrUpdate 方法以线程安全的方式将项目添加到列表中。它更简单并且应该可以正常工作。

var list1 = new ConcurrentDictionary<int, IList<string>>();
list1.AddOrUpdate(key, 
      new List<string>() { "test" }, (k, l) => { l.Add("test"); return l;});
Run Code Online (Sandbox Code Playgroud)

UPD

根据文档消息来源,传递给AddOrUpdate方法的工厂将超出锁定范围,因此List在工厂委托内调用方法不是线程安全的。

请参阅此答案下的评论。