我遇到了 .NET 3.5 的 ConcurrentDictionary
实现(很抱歉我现在可以找到链接),它使用这种锁定方法:
var current = Thread.CurrentThread.ManagedThreadId;
while (Interlocked.CompareExchange(ref owner, current, 0) != current) { }
// PROCESS SOMETHING HERE
if (current != Interlocked.Exchange(ref owner, 0))
throw new UnauthorizedAccessException("Thread had access to cache even though it shouldn't have.");
代替传统的lock
:
lock(lockObject)
{
// PROCESS SOMETHING HERE
}
问题是:这样做有什么真正的理由吗?它是更快还是有一些隐藏的好处?
PS:我知道在某些最新版本的 .NET 中有一个 ConcurrentDictionary
,但我不能将其用于遗留项目。
编辑:
在我的特定情况下,我所做的只是以线程安全的方式操作内部 Dictionary
类。
例子:
public bool RemoveItem(TKey key)
{
// open lock
var current = Thread.CurrentThread.ManagedThreadId;
while (Interlocked.CompareExchange(ref owner, current, 0) != current) { }
// real processing starts here (entries is a regular `Dictionary` class.
var found = entries.Remove(key);
// verify lock
if (current != Interlocked.Exchange(ref owner, 0))
throw new UnauthorizedAccessException("Thread had access to cache even though it shouldn't have.");
return found;
}
正如@doctorlove 所建议的,这是代码:https://github.com/miensol/SimpleConfigSections/blob/master/SimpleConfigSections/Cache.cs
最佳答案
您的问题没有明确的答案。我会回答:视情况而定。
您提供的代码的作用是:
- 等待对象处于已知状态(
threadId == 0 == no current work
) - 工作
- 将已知状态设置回对象
- 现在另一个线程也可以工作了,因为它可以从第 1 步转到第 2 步
正如您所注意到的,代码中有一个循环实际执行“等待”步骤。 您不会阻塞线程,直到您可以访问您的关键部分,您只是消耗 CPU 而不是。尝试用 Thread.Sleep(2000)
替换您的处理(在您的情况下,调用 Remove
),您会看到另一个“等待”线程消耗了所有你的一个 CPU 循环 2s。
也就是说,哪个更好取决于几个因素。例如:有多少个并发访问?手术需要多长时间才能完成?你有多少个 CPU?
我会使用 lock
而不是 Interlocked
因为它更容易阅读和维护。异常(exception)情况是您有一段代码被调用了数百万次,并且您确定 Interlocked
更快的特定用例。
因此您必须自己衡量这两种方法。如果您没有时间这样做,那么您可能不需要担心性能问题,您应该使用 lock
。
关于c# - Interlocked.CompareExchange 真的比简单的锁更快吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20800954/