编译器是否允许将存储操作重排至条件判断前?原子变量场景分析
编译器能否将存储操作重排至条件判断之前?
先看原始代码:
int test(bool* flag, int* y) { if(*y) { *flag = false; } else { *flag = true; } }
编译器可确定此处一定会对flag执行写入操作,因此可能将代码改写为如下形式:
int test(bool* flag, int* y) { *flag = true; if(*y) { *flag = false; } }
从单线程的as-if规则角度看,这种改写似乎合法,但存在疑问:如果*y恒为true,那么flag最终值应为false,但其他线程读取flag时可能读到临时写入的true,这是否违反as-if规则?该优化是否合法?
补充说明:非原子变量的情况属于未定义行为(UB),无需讨论;以下仅分析flag为采用relaxed ordering的原子变量的场景。
核心结论:该优化合法,不违反规则
1. 单线程视角下符合as-if规则
as-if规则的核心是保证单线程程序的可观察行为不变。在单线程中,无论*y取值如何,改写后的代码最终flag的结果和原始代码完全一致:
- 若
*y为true,最终flag会被覆盖为false; - 若
*y为false,flag保持true。
单线程中不会观察到中间写入的true值,因此完全符合as-if规则,编译器的改写是合法的。
2. 多线程场景下符合relaxed原子的语义
对于relaxed顺序的原子变量:
- 它仅保证读写操作的原子性,不提供任何内存顺序约束——既不禁止编译器对原子操作的重排,也不保证操作顺序对其他线程的可见性。
- 其他线程读到临时的
true值,属于relaxed原子语义允许的情况。C++内存模型并未要求relaxed原子操作屏蔽这种中间状态的可见性,因此这种优化并未违反标准。
简言之,编译器的这个重排优化在单线程下完全合规,在relaxed原子的多线程场景下也合法,因为relaxed语义本身就允许此类行为。
内容的提问来源于stack exchange,提问作者Moshe Levy
相关产品推荐
相关产品推荐

