并发的fetch_add和compare_exchange_weak交互

问题描述 投票:0回答:1

考虑 T1 和 T2 之间的以下交互。 T2 是否会错过 T1 的通知而暂停? 换句话说,是否会发生

compare_exchange_weak
成功而T1读取到的值不是
THREAD_SLEEP
aftercompare_exchange_weak成功?

我很困惑,因为在这个例子中,除了

tq_seq_
之外没有其他共享内存变量,所以为什么内存顺序很重要?

#define THREAD_SLEEP 10000000

// T1: Producer Thread
void T1() {
    auto current = tq_seq_.fetch_add(1, std::memory_order_relaxed);
    if (current == THREAD_SLEEP) {
        WakeT2();
    }
}

// T2: Consumer Thread
void T2() {
    while (true) {
        auto start_seq = tq_seq_.load(std::memory_order_acquire);
        // ... (perform some if any)
       
        // Attempt to sleep if no notifications arrived
        if (tq_seq_.compare_exchange_weak(
                start_seq,
                THREAD_SLEEP,
                std::memory_order_acquire)) {
            thread_suspend(); // Suspend T2 until woken by T1
        }
    }
}
c++ atomic compare-and-swap
1个回答
0
投票

也就是说,会不会出现compare_exchange_weak成功后,T1在

THREAD_SLEEP
成功后读取到的不是
compare_exchange_weak
的值?

是的,这是可能的,因为

fetch_add
(或 C++ 中的任何其他原子操作)不能保证对最新值(实时)进行操作。

tq_seq_.fetch_add(1, std::memory_order_relaxed)
都会

  • 读取旧值(例如,
    42
    ),递增并写入更新的值(
    43
    ),或者
  • 读取最新值
    THREAD_SLEEP
    ,递增并写入
    THREAD_SLEEP + 1

因此,可能的事件顺序是:

  1. T1 来电
    WakeT2()
  2. T2 醒来并开始工作
  3. T2 上的
  4. compare_exchange_weak
    成功,但其效果不会立即对 T1 可见
  5. T1 稍后(实时)调用
    fetch_add
    ,读取
    42
    并写入
    43
  6. compare_exchange_weak
    的效果现在变得可见,如果T1现在假设调用
    fetch_add
    ,它将读取
    THREAD_SLEEP
    并写入
    THREAD_SLEEP + 1

然而,你可能担心的,也是绝对不可能的是,T1读取

42
,观察到
THREAD_COUNT
被写入,并写入
43
,从而“吞掉”或“覆盖”效果
compare_exchange_weak
就好像它从未发生过一样。

© www.soinside.com 2019 - 2024. All rights reserved.