【问题标题】:Non-blocking locking- Validation of concept and follow-up非阻塞锁定-概念验证和跟进
【发布时间】:2013-07-18 16:29:24
【问题描述】:

这更像是一个概念问题的验证。我希望我没有违反关于 SO 的可接受问题规则。我尝试在答案线程上发表评论,但 SO 不允许我这样做。

从这个问题的公认答案开始,我也有这个问题 - Non blocking locking

接受答案的选项 2 是这样的:

private int _inUseCount;

public void MyMethod()
{
    if (Interlocked.Increment(ref _inUseCount) == 1)
    {
        // do some stuff    
    }
    Interlocked.Decrement(ref _inUseCount);
}

似乎执行增量的线程不一定是执行代码的“//做一些事情”部分的线程。

考虑这种情况:

  • ThreadA 将 _inUseCount 增加到 1 并暂停
  • ThreadB 将 _inUseCount 增加到 2 并暂停
  • ThreadA 恢复并看到 _inUseCount 等于 2,不执行代码的“做一些事情”部分,将 _inUseCount 递减为 1 并完成
  • ThreadB 恢复并看到 _inUseCount 为 1 并执行代码的“做一些事情”部分

有没有办法使用这种范式来确保执行增量的线程是执行代码的线程?

【问题讨论】:

    标签: c# .net multithreading


    【解决方案1】:

    执行增量的线程不一定是执行“//do some stuff”的线程

    这是错误的。它们是一个代码路径的一部分,将在同一个线程上执行。

    但只有当线程在启动时找到_inUseCount==0 时,它才会执行“一些东西”。否则它将跳过该部分。


    考虑这种情况:

    • ThreadA 将 _inUseCount 增加到 1 并暂停
    • ThreadA 恢复并看到 _inUseCount 等于 2,不执行代码的“做一些事情”部分,递减 _inUseCount 到 1 并结束

    ThreadA 执行if (Interlocked.Increment(ref _inUseCount) == 1) 并且它是Interlocked.Increment() 的合约,这个线程将看到它自己的增量所做的返回值。

    因此,虽然 "ThreadA 恢复并看到 inUseCount 等于 2" 是可能的,但这不是代码所做的。它查看Increment() 的返回值,不依赖于任何挂起/恢复场景。

    【讨论】:

    • 嗨@HenkHolterman。感谢您的回答。考虑这种情况 - ThreadA 将 _inUseCount 增加到 1 并挂起,ThreadB 将 _inUseCount 增加到 2 并挂起。 ThreadA 恢复并看到 _inUseCount 等于 2,不执行代码的“做一些事情”部分,将 _inUseCount 递减为 1 并结束。 ThreadB 恢复并看到 _inUseCount 为 1 并执行代码的“做一些事情”部分。
    • 将此添加到问题中。但是Interlocked 让你的场景变得不可能。
    • 据我了解,Interlocked.Increment 将执行变量的增量并将其存储回一个原子操作中。关于 Interlocked 的工作原理,我是否遗漏了什么让你说我的场景是不可能的?
    • @HenkHolterman- 感谢您更新的答案。如果这就是 Interlocked.Increment 的工作方式,那么它肯定会让我的场景变得不可能。我猜一旦值增加和存储,就会发生一些缓存。所以我可以说,这个增量和缓存是一个原子操作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-06-08
    • 1970-01-01
    • 2020-01-15
    • 2014-03-23
    • 2011-01-25
    • 2013-03-13
    相关资源
    最近更新 更多