【问题标题】:How to ensure the comparison result still hold in multi-threading?如何确保比较结果在多线程中仍然成立?
【发布时间】:2022-01-18 12:13:17
【问题描述】:

假设有3个线程,

线程 1 和 2 将自动增加或减少全局变量 X。

线程 1:

atomic_increase(X)

线程 2:

atomic_decrease(X)

线程 3 将检查 X 是否大于某个预定义的值并相应地执行操作。

线程 3:

if( X > 5 ) {... logic 1 ...}
else {... logic 2 ....}

我认为atomic_xxx 操作还不够。它们只能在线程 1 和 2 之间同步修改。

如果X被线程1或2更改在线程3完成比较后进入logic 1

修改或读取X时是否必须使用互斥锁来同步所有3个线程?

添加 1

顺便说一句,逻辑 1 和逻辑 2 不会修改 X。

【问题讨论】:

    标签: multithreading atomic


    【解决方案1】:

    简而言之,读取也需要以某种方式同步,否则读取不一致的风险是真实存在的。在atomic_increase 的读取和写入之间执行的读取将不一致。

    但是,如果logic 1logic 2X 做事,您的问题似乎并没有就此停止。我认为您需要事务的概念,它以读取(X > 5 事物)开始,然后以写入(logic 1logic 2)结束。

    【讨论】:

    • 谢谢。顺便说一句,逻辑 1 和逻辑 2 不会修改 X。
    【解决方案2】:

    是的,答案是happens before 链接,假设Thread-1 开始执行atomic_increase 方法。它将持有lock 并进入synchronized 块以更新X

    private void atomic_increase() {
        synchronized (lock) {
            X = X + 1;  // <-- Thread-1 entered synchronized block, yet to update variable X
        }
    }
    

    现在,Thread-3 要运行逻辑,它需要读取变量 X,如果是 not synchronized(在同一监视器上),则变量 X 读取可以是旧值,因为Thread-1 可能还没有更新。

    private void runLogic() {
        if (X > 5) { // <-- Reading X here, can be inconsistent no 
                       happens-before between atomic_increase and runLogic
        } else {
    
        }
    }
    

    我们可以通过在atomic 操作和run_logic 方法之间维护happens-before 链接来防止这种情况发生。如果runLogicsynchronized(在同一监视器上),那么它必须等到变量XThread-1 更新。所以我们保证得到X的最后更新值

    private void runLogic() {
        synchronized (lock) {
            if (X > 5) { // <-- Reading X here, will be consistent, since there 
                           is happens-before between atomic_increase and runLogic 
            } else {
    
            }
        }
    }
    

    【讨论】:

      【解决方案3】:

      答案取决于您的应用程序做什么。如果逻辑 1 和逻辑 2 都没有修改 X,则很有可能不需要额外的同步(除了使用 atomic_load 读取 X)。

      我假设您将内在函数用于原子操作,而不仅仅是互斥体(或 Java 中的同步块)中的增量。例如。在 Java 中,有一个 AtomicInteger 类,其中包含“incrementAndGet”和“get”等方法。如果你使用它们,可能不需要额外的同步,但这取决于你真正想用逻辑 1 或逻辑 2 实现什么。

      如果你想,例如当X &gt; 5时显示一条消息,然后你就可以做到了。到消息显示时,X 的值可能已经改变,但事实仍然是,消息是由 X 至少在一段时间内大于 5 触发的。

      换句话说,如果没有额外的同步,您只能保证如果X 大于 5 将调用逻辑 1,但不能保证在执行逻辑 1 期间它会保持这种状态。可能是对你好不好。

      【讨论】:

      • 所以要看逻辑1是什么。
      • @smwikipedia 这也取决于逻辑 2 是什么。当X &lt;= 5 时没有额外的同步逻辑2 将被调用,但在逻辑2 执行期间X 可能会并行增加,例如,6 或更多。如果逻辑 2 没问题,那就没问题了。
      猜你喜欢
      • 1970-01-01
      • 2019-04-22
      • 1970-01-01
      • 2010-11-28
      • 1970-01-01
      • 1970-01-01
      • 2021-12-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多