锁的正确使用位置在哪里

发布于 2024-12-10 17:14:53 字数 377 浏览 5 评论 0原文

我尝试在多线程环境中找到最好的相似性。

有没有更好的替代方案或者下面两个版本相同?

 // float bestSimilarity is shared
 // float _similarity is local

 lock(locker) 
     if (_similarity > bestSimilarity)
         bestSimilarity = _similarity;

 if (_similarity > bestSimilarity)
     lock(locker) 
         bestSimilarity = _similarity;

I try to find the best similarity in multithreaded environment.

Is there any better alternative or both versions are same below?

 // float bestSimilarity is shared
 // float _similarity is local

 lock(locker) 
     if (_similarity > bestSimilarity)
         bestSimilarity = _similarity;

vs

 if (_similarity > bestSimilarity)
     lock(locker) 
         bestSimilarity = _similarity;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

往事随风而去 2024-12-17 17:14:53

您的第一个案例将有保证。然而,第二种情况可能会失败。您进行比较,然后请求锁定,同时另一个线程已经修改了 bestSimilarity,而您却不知道它使比较无效。

如果你想避免直到最后一刻才被锁定,你可以进行两次比较。也就是说,比较,获取锁,再次比较,只有当它仍然有效时,才增加该值。但要小心您要比较的值的本地缓存。如果你想做到这一点,你需要有某种同步,比如 MemoryBarrier。这一切可能会变得非常复杂,所以我建议锁定整个事情,除非您注意到性能确实是一个瓶颈

Your first case will work guaranteed. The second case however might break down. You compare, then request a lock while in the meantime another thread already modifies bestSimilarity without you knowing of it making the comparison invalid.

If you want to avoid the lock untill the last minute, you can do a comparison twice. That is, compare, acquire a lock, compare again and only if its still valid, increase the value. Be carefull though with local cache of the value you're comparing against. If you want to do this, you need to have some kind of synchronization there like a MemoryBarrier. This all can get pretty complex so i recommend just lock the whole thing unless you notice performance really is a bottleneck

允世 2024-12-17 17:14:53

由于 bestSimilarity 是共享的,因此您需要使用第一个代码段

As bestSimilarity is shared, you will need to use the first code segment

︶ ̄淡然 2024-12-17 17:14:53

第二个不是线程安全的,在执行 if 测试后另一个线程可能会更改 _similarity

The second is not thread safe, another thread could change _similarity after the if test has been performed.

草莓酥 2024-12-17 17:14:53

第一个解决方案是线程安全的,第二个则不是。
但是,您可以使用双重检查锁来减少获取锁的开销

if (_similarity > bestSimilarity)  
{
    lock(locker) 
    {
         if (_similarity > bestSimilarity)
             bestSimilarity = _similarity;
    }
}

The first solutions is thread safe - the second is not.
However you can use double-checked lock to reduce the overhead of acquiring a lock

if (_similarity > bestSimilarity)  
{
    lock(locker) 
    {
         if (_similarity > bestSimilarity)
             bestSimilarity = _similarity;
    }
}
浸婚纱 2024-12-17 17:14:53

您也可以无锁地执行此操作:

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) 到快照(这是稳定的,作为本地)
  • 如果它更高,它会交换值但仅当累加器没有改变
  • 如果累加器已经改变,它再次完成整个事情

这是完全线程安全的,并且是无锁的

You could also do it lock-free:

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);

This:

  • takes a snapshot of bestSimilarity at the start (which I assume is the accumulator)
  • it then compares our current value (_similarity) to the snapshot (which is stable, as a local)
  • if it is higher, it swaps in the value but only if the accumulator hasn't changed
  • if the accumulator has changed, it does the whole thing again

This is fully thread-safe, and lock-free

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文