35

的文档ConcurrentDictionary没有明确说明,所以我想我们不能指望委托valueFactoryupdateValueFactory他们的执行同步(分别来自 GetOrAdd() 和 AddOrUpdate() 操作)。

[MethodImpl(MethodImplOptions.Synchronized)]因此,我认为如果不手动实现我们自己的并发控制(可能只是使用委托),我们就无法实现它们内部需要并发控制的资源的使用。

我对吗?还是线程安全的事实,ConcurrentDictionary我们可以期望对这些委托的调用会自动同步(也是线程安全的)?

4

2 回答 2

36

是的,你是对的,用户代表不同步ConcurrentDictionary。如果你需要那些同步的,那是你的责任。

MSDN 本身说:

此外,虽然 ConcurrentDictionary 的所有方法都是线程安全的,但并非所有方法都是原子的,特别是 GetOrAdd 和 AddOrUpdate。传递给这些方法的用户委托是在字典的内部锁之外调用的。(这样做是为了防止未知代码阻塞所有线程。)

请参阅“如何:从 ConcurrentDictionary 添加和删除项目

这是因为ConcurrentDictionary不知道您提供的委托将做什么或它的性能,所以如果它试图锁定它们,它可能会对性能产生负面影响并破坏 ConcurrentDictionary 的价值。

因此,如果有必要,用户有责任同步他们的委托。上面的 MSDN 链接实际上有一个很好的例子来说明它做和不做的保证。

于 2012-05-07T17:48:32.033 回答
27

这些委托不仅不同步,甚至不能保证只发生一次。事实上,它们可以在每次调用AddOrUpdate.

例如,算法AddOrUpdate看起来像这样。

TValue value;
do
{
  if (!TryGetValue(...))
  {
    value = addValueFactory(key);
    if (!TryAddInternal(...))
    {
      continue;
    }
    return value;
  }
  value = updateValueFactory(key);
} 
while (!TryUpdate(...))
return value;

这里注意两点。

  • 没有努力同步代表的执行。
  • 代表可能会被执行多次,因为它们是在循环内调用的。

所以你需要确保你做两件事。

  • 为代表提供您自己的同步。
  • 确保您的代理没有任何取决于执行次数的副作用。
于 2012-05-07T19:34:14.360 回答