【发布时间】:2021-04-27 13:46:20
【问题描述】:
我一直在学习由 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,但它的键/值对可能不会在每次调用时都添加到字典中。 p>
如果是这样的话,我一直在 source.dot.net 上查看AddOrUpdate 的源代码,我看不到任何地方正在使用任何锁,我可以看到TryAddInternal和TryUpdateInternal。
无论如何,前面发布的方法有效,但我不明白它为什么有效,一旦我删除看似不必要的success = false 分配,它就不起作用了,就会出现不匹配。所以我很好奇是什么让这些代表在失败后重蹈覆辙?
我的问题是:
1。如图所示使用AddOrUpdate 是否安全,或者我应该锁定所有内容并忘记它?
2。是什么让代表在被打断后重复自己?它与“比较和交换”有什么关系吗? (对这个最好奇);
3。是否有任何主题/概念让我查看以更好地了解线程安全环境?
【问题讨论】:
标签: c# concurrency thread-safety atomic concurrentdictionary