volatile与_Atomic语义结合的疑问:原子RMW操作的实现保障
关于C语言中
volatile _Atomic原子RMW操作的语义保障 基础语义背景
在C语言中,_Atomic并不隐含volatile语义——原子对象上的操作不属于编译器必须保留的可观察副作用。因此像下面的代码:
void f(_Atomic int* x) { atomic_fetch_add_explicit(x, 0, memory_order_relaxed); }
编译器有权将其优化为空操作,其中Clang会执行该优化,而GCC与MSVC不会。
volatile _Atomic的行为分歧
按预期,组合volatile与_Atomic限定符应该能结合两者的语义,比如下面的代码:
void f(volatile _Atomic int* x) { atomic_fetch_add_explicit(x, 0, memory_order_relaxed); }
本应迫使编译器生成对x执行原子读-改-写(RMW)操作的指令。但Clang的行为仅符合预期的一部分:它生成的汇编代码只包含加载指令,没有存储操作,并非完整的原子RMW操作。
标准层面的语义保障分析
核心疑问是:对于volatile原子RMW操作,实现应当提供哪些保障?
根据ISO C草案N3220 §3.1的定义,“访问”指的是读取或修改对象值的执行时操作,该定义并未将原子RMW操作视为单个访问。但从语义逻辑和标准要求推导:
volatile的核心要求是:对volatile对象的每一次读取或修改操作都必须被保留,不能被编译器优化消除。- 原子RMW操作本质是“读取-修改-存储”的原子性组合,对于
volatile _Atomic对象来说,读取部分必须是volatile加载,修改后的存储部分也必须是volatile存储,且这两个步骤必须合并为一个原子RMW操作(否则会破坏原子性语义)。
因此,实现至少应当保证:volatile原子RMW操作同时等价于volatile读取和volatile修改,且二者必须合并为单个原子RMW访问(具体实现方式可由实现定义)。
Clang当前只保留加载操作的行为,既违背了volatile对修改操作的保留要求,也不符合原子RMW的语义,更倾向于是一个实现Bug。
内容的提问来源于stack exchange,提问作者user17732522
相关产品推荐
相关产品推荐

