compare_exchange_strong/weak在松弛内存序下是否可能读取到旧值?
你给出的测试代码如下:
atomic_int x = 0; void thread1() { int a = atomic_load_explicit(&x, memory_order_relaxed); compare_exchange_strong_explicit(&x, &a, 1, memory_order_relaxed, memory_order_relaxed); a = atomic_load_explicit(&x, memory_order_relaxed); } void thread2() { int a = 0; compare_exchange_strong_explicit(&x, &a, 2, memory_order_relaxed, memory_order_relaxed); }
问题1:thread1的CAS操作是否可能成功?
答案是否定的,该场景下CAS必然失败。compare_exchange_strong_explicit属于原子读-修改-写(RMW)操作,执行时会原子读取原子变量x的当前值,和预期值(这里是thread1之前load到的0)做对比:相等才写入新值1,操作成功;不等则把当前读到的x的最新值写入a指向的地址,操作失败。
你已经假设thread2的CAS成功把x修改为2,此时x的全局修改顺序中0→2的修改已经完成。哪怕使用的是最弱的memory_order_relaxed,也只影响不同变量之间的操作顺序约束,同一个原子变量的原子性、一致性约束依然生效,CAS作为原子RMW操作必然能读到全局修改顺序中排在它之前的最新值2,和预期的0不匹配,因此一定会失败。
问题2:thread1后续的第二次relaxed load是否可能读到旧值0?
答案是否定的,不可能读到0。
C++内存模型对同一个原子对象有明确的一致性(coherence)要求:
- 所有线程对同一个原子对象的修改,存在唯一的全局修改顺序
- 同一个线程对同一个原子对象的所有操作,严格按程序顺序参与到这个全局修改顺序中,后执行的操作必然能看到至少和前序操作一样新的值
thread1的CAS操作已经读取到了x的最新值2,后续的load操作在程序顺序上晚于CAS,因此必然能看到至少和CAS读到的一样新的值,不可能读到更旧的0。
问题3:CAS操作是否会强制当前线程的内存子系统刷新对应变量的缓存?
C++标准本身不规定缓存相关的硬件实现细节,只定义了内存可见性的语义约束,但主流硬件平台的实现逻辑是一致的:
原子RMW操作(包括CAS)无论使用什么内存序,都需要先获得该变量对应缓存行的独占所有权(x86平台用lock前缀触发缓存一致性协议同步,ARM平台用独占监视器机制实现),这个过程本身就会把当前缓存行同步为全局最新状态,不存在读旧值的可能。执行完CAS之后,当前CPU核心的缓存中该变量的值已经是最新的,后续的同变量读取操作直接读本地缓存即可,不需要额外刷新,也不可能读到旧值。
内容的提问来源于stack exchange,提问作者Skyfarmer
相关产品推荐
相关产品推荐

