C++原子操作:无对应memory_order_release的memory_order_acquire使用问询
原子操作内存序问题解答
1. 是否存在memory_order_acquire加载无对应memory_order_release存储的场景?
当然存在。memory_order_acquire的核心作用是阻止当前线程中后续的读写操作被重排到该加载操作之前,同时如果该加载操作读取到了其他线程用memory_order_release写入的值,会建立同步关系。但它本身不强制要求必须有对应的memory_order_release操作——只是没有release的话,acquire的同步可见性作用会失效,只剩下禁止重排的功能。
2. 示例代码中线程2是否可能先看到(B)的更新,再看到(A)的更新?
是的,完全有可能。原因如下:
- 线程1中的(A)(compare_exchange成功分支)和(B)都是
memory_order_relaxed语义,编译器或CPU可以对这两个操作重排,甚至在内存层面让(B)的更新更早被其他线程观测到; - 线程2的(C)是
memory_order_acquire,只能保证自身线程中(D)不会被重排到(C)之前,但无法约束线程1的操作顺序,也无法保证看到(A)的同时一定能看到(B)。
所以线程2完全可能出现:count_val已经是更新后的值,但state_val还是旧值的情况。
3. 如何确保线程2加载state时总能看到对应的count更新?
不需要调换(C)和(D)的顺序,正确的修改方式是:
- 将线程1中(A)操作的成功内存序改为
memory_order_release(compare_exchange_weak的第三个参数是成功时的内存序); - 线程2中的(C)保持
memory_order_acquire不变。
修改后的线程1代码片段:
if (state.compare_exchange_weak(expected, desired, memory_order_release, memory_order_relaxed)) { // (A) count.fetch_add(1, memory_order_relaxed); // (B) break; }
这样一来,线程1的(A)(release语义)和线程2的(C)(acquire语义)会建立release-acquire同步关系:线程1中(A)之前(包括(A)本身)的所有写入操作,对成功读取到(A)写入值的线程2来说都是可见的。由于线程1中(B)是在(A)成功后执行的,release语义会阻止(B)被重排到(A)之前,所以线程2看到(A)的新值时,必然能看到(B)的更新。
内容的提问来源于stack exchange,提问作者ktqq99
相关产品推荐
相关产品推荐

