哪里是使用锁的正确位置
本文关键字:位置 | 更新日期: 2023-09-27 18:11:43
我尝试在多线程环境中找到最好的相似性。
是否有更好的替代方案或两个版本相同?
// float bestSimilarity is shared
// float _similarity is local
lock(locker)
if (_similarity > bestSimilarity)
bestSimilarity = _similarity;
和
if (_similarity > bestSimilarity)
lock(locker)
bestSimilarity = _similarity;
您的第一个案例将保证工作。然而,第二种情况可能会失效。你比较,然后请求一个锁,而同时另一个线程已经在你不知道的情况下修改了bestSimilarity,使得比较无效。
如果您想在最后一刻才使用锁,可以进行两次比较。也就是说,比较,获取锁,再次比较,只有当锁仍然有效时,才增加值。不过,要小心要比较的值的本地缓存。如果你想这样做,你需要有一些同步,比如MemoryBarrier。这些会变得非常复杂所以我建议你把所有东西都锁起来除非你注意到性能真的是个瓶颈
由于bestSimilarity
是共享的,您将需要使用第一个代码段
第二个线程不是线程安全的,在执行if测试后,另一个线程可能会改变_similarity
。
第一个解决方案是线程安全的-第二个不是。但是,您可以使用双重检查锁来减少获取锁的开销
if (_similarity > bestSimilarity)
{
lock(locker)
{
if (_similarity > bestSimilarity)
bestSimilarity = _similarity;
}
}
也可以设置为无锁:
bool retry;
do
{
retry = false;
var copy = Interlocked.CompareExchange(ref bestSimilarity, 0, 0);
if (_similarity > copy)
{
retry = Interlocked.CompareExchange(
ref bestSimilarity, _similarity, copy) != copy;
}
} while (retry);
:
- 在开始时(我假设是累加器)拍摄
bestSimilarity
的快照 然后比较我们的当前值( - 如果值更高,则只在累加器没有改变 的情况下交换值。
- 如果累加器改变了,它将重新执行整个操作
_similarity
)和快照(这是稳定的,作为一个本地)这是完全线程安全的,无锁的