这是在ConcurrentDictionary上使用AddOrUpdate的可靠方法吗



我一直在学习由Simon Robinson撰写的关于并发收藏的Pluralsight课程。

他以以下方式使用AddOrUpdate以使其线程安全:

public bool TrySellShirt(string code)
{
bool success = false;
_stock.AddOrUpdate(code, 
(itemname) => { success = false; return 0; },
(itemName, oldValue) =>
{
if (oldValue == 0)
{
success = false;
return 0;
}
else
{
success = true;
return oldValue - 1;
}
});
if (success)
Interlocked.Increment(ref _totalQuantitySold);
return success;
}

所以,我知道AddOrUpdate并不完全是原子的,正如它在文档中所说:">addValueFactory和updateValueFactory委托在锁外调用,以避免在锁下执行未知代码时可能出现的问题";

这一点我很清楚。尚不清楚的是,在代理中将success设置为false有什么意义。AddValueFactory参数被有意用作lambda,因此可以设置success = false,而不仅仅是返回0。我有点理解/认为,如果方法lambda被另一个线程中断(它可能会被中断,因为它是在锁外调用的(,它将尝试重复自己,因此我们应该将任何相应值的状态设置为其初始值,以干净地参与新的迭代,从而设置success = false;

同样来自文档:如果在不同的线程上同时调用AddOrUpdate,addValueFactory可能会被多次调用,但其键/值对可能不会在每次调用时都添加到字典中

如果是这样的话,我一直在source.dot.net上检查AddOrUpdate的源代码,我看不到任何地方使用了任何锁,我可以看到TryAddInternalTryUpdateInternal

无论如何,前面提到的方法是有效的,但我不明白为什么它有效,而且一旦我删除了看似不必要的success = false赋值,它就不起作用了,这就是不匹配。所以我很好奇,是什么让这些代表在失败后重复自己?

我的问题是:

1。如图所示使用AddOrUpdate安全吗?还是我应该锁定所有内容并忘记它?

2。是什么让学员在被打断后重复自己的话?它与"比较和交换"有什么关系吗?(最好奇的是这个(;

3。为了更好地理解线程安全环境,有什么主题/概念需要我检查吗?

因为addValueFactoryupdateValueFactory委托是由ConcurrentDictionary在没有任何锁的情况下调用的,所以在运行add/updateValueFactory代码时,另一个线程可能会更改字典的内容。为了处理这种情况,如果调用了addValueFactory(因为字典中不存在键(,它只会在字典中仍然不存在键的情况下添加返回值。类似地,如果调用了updateValueFactory,则仅当当前值仍然是oldValue时,才会更新键的值。

如果在add/updateValueFactory代码运行时,由于另一个线程添加/更新/删除了相同的密钥而导致不匹配,它将简单地尝试根据字典的最新内容再次调用适当的委托(委托不会被"中断",而是字典本身再次调用它们——添加/更新的键的值已经更改(。这解释了为什么即使success被初始化为false,仍然需要在lambdas中分配success = false。以下示例可能有助于可视化行为:

初始字典状态:_stock["X"] = 1

//tr>调用_stock.AddOrUpdate("X", ...)[/tr>设置success = true,返回oldValue - 1=0//tr>success的最终值是true[/tr>
步骤 线程1 线程2
1 调用_stock.AddOrUpdate("X", ...)
2 updateValueFactory已调用(旧值=1(
3
4 调用updateValueFactory(旧值=1(
5
6 字典检查关键字";X〃;仍然=1(true(
7 密钥的值";X〃;更新为0
8 设置success = true,返回oldValue - 1=0
9 字典检查关键字";X〃;仍然=1(false(
10 updateValueFactory再次调用(旧值=0(
11 设置success = false,返回0
12 字典检查关键字";X〃;仍然=0(true(
13 键的值";X〃;更新为0
14 success的最终值为false

相关内容

  • 没有找到相关文章

最新更新