原子读-改-写操作是否为单一不可分操作?标准意图解析
原子Read-Modify-Write(RMW)操作的原子性与内存同步问题
关于原子RMW操作的本质,存在两种看似矛盾的表述:
- CWG成员Jens Maurer明确指出read-compare-write是单一、不可分的原子操作;
- 社区普遍认为RMW操作包含读、写两个步骤,这也符合C++标准[atomics.order] p10的描述:“原子读-改-写操作应始终读取其关联写入操作之前(修改顺序中)的最后写入值”——条款直接提到了RMW关联的“读”和“写”动作。
这就带来疑问:标准此处的真实意图是什么?再结合以下代码示例,还需要明确RMW操作的内存序语义是否能触发线程间同步:
std::atomic<int> x{0}; // 线程1: int expected = 0; x.compare_exchange_strong(expected, 1, std::memory_order::release, std::memory_order::relaxed); // #1 // 线程2: int expected = 1; while( /*#2*/ x.compare_exchange_strong(expected, 2, std::memory_order::acquire, std::memory_order::relaxed) ){}
假设线程2的RMW操作一次就读取到线程1写入的值(即#2仅执行一次循环),结合标准条款分析:
[atomics.order] p2:对原子对象M执行release操作的原子操作A,与对M执行acquire操作且取值来自A领头的释放序列中任何副作用的原子操作B同步。
[atomics.order] p1:memory_order::release、memory_order::acq_rel和memory_order::seq_cst:存储操作对受影响的内存位置执行release操作。memory_order::acquire、memory_order::acq_rel和memory_order::seq_cst:加载操作对受影响的内存位置执行acquire操作。
关键结论
1. RMW操作的原子性与语义描述的关系
需要从两个层面理解:
- 原子性保证层面:Jens Maurer的表述是从"操作不可分性"出发——RMW作为一个整体,不会被其他线程的原子操作打断,其他线程不可能观察到RMW执行到一半的中间状态,这是RMW的核心原子性承诺。
- 语义规则层面:标准条款提到的"读"和"写"是对RMW内部逻辑的拆分描述,用于定义其内存顺序行为和修改顺序规则,并不否定其作为整体的原子性。
2. 线程1与线程2的同步关系
- 当#1的
compare_exchange_strong操作成功时,其内部的存储部分会执行release语义; - 当#2的
compare_exchange_strong操作成功时,其内部的加载部分会执行acquire语义; - 由于#2读取到的值来自#1的写入(属于#1领头的释放序列),根据[atomics.order] p2,#1和#2会建立同步关系:#1的所有可见副作用对#2线程可见,且#1的操作在#2的操作之前完成。
内容的提问来源于stack exchange,提问作者xmh0511
相关产品推荐
相关产品推荐

