考虑 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
}
}
}
也就是说,会不会出现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
因此,可能的事件顺序是:
WakeT2()
compare_exchange_weak
成功,但其效果不会立即对 T1 可见fetch_add
,读取 42
并写入 43
compare_exchange_weak
的效果现在变得可见,如果T1现在假设调用fetch_add
,它将读取THREAD_SLEEP
并写入THREAD_SLEEP + 1
然而,你可能担心的,也是绝对不可能的是,T1读取
42
,观察到THREAD_COUNT
被写入,并写入43
,从而“吞掉”或“覆盖”效果compare_exchange_weak
就好像它从未发生过一样。