Delphi开启优化后Win32平台AtomicCmpExchange异常问题咨询
问题原因
你遇到的是Delphi 10.4 Sydney Update 3 Win32 编译器的已知优化Bug,你提到的“崩溃”实际是代码逻辑触发的主动异常,根本原因如下:
该版本编译器对内置原子操作的副作用识别不完整,且未正确实现原子操作自带的编译器内存屏障:
- 当
AtomicCmpExchange的返回值未被显式捕获时,开启优化后编译器会错误地对该调用的相关代码做乱序重排,甚至可能直接判定该调用无副作用而将其优化移除。 - 同时编译器会将类成员变量
FKey缓存到CPU寄存器中,原子操作修改了内存中的FKey值,但后续的比较逻辑读取的是寄存器中未更新的缓存值,才会触发Error 2的异常。
替代解决方案(无需关闭优化)
- 方案1:显式捕获
AtomicCmpExchange的返回值,哪怕不使用返回值,也能让编译器识别到该调用的副作用,不会错误优化:
把原调用代码修改为:var _ := AtomicCmpExchange(FKey{target}, LCompareKey{NewValue}, LCompareKey{Comparand}); - 方案2:在原子操作和后续比较之间插入编译器内存屏障,强制刷新寄存器缓存的变量值,在
AtomicCmpExchange调用后添加一行即可:System.MemoryBarrier; - 方案3:将
FKey标记为易失变量,禁止编译器对该变量做寄存器缓存和访问乱序,修改变量声明即可:private {$VOLATILE ON} FKey: integer; {$VOLATILE OFF} - 方案4:升级到Delphi 11 Alexandria及以上版本,该编译器Bug已经在后续版本中修复。
编译优化的安全性说明
正常情况下开启编译优化是安全的。Delphi的官方优化逻辑严格遵循Pascal语言规范,优化仅会在不改变代码合法逻辑的前提下,提升程序运行效率、减小最终生成的二进制体积。
仅两种情况可能出现优化后逻辑异常:
- 代码本身存在未定义行为,比如多线程同步缺失、依赖编译器未明确约定的实现细节;
- 遇到了极少数的编译器自身Bug,本次你遇到的就是这类个例,这类问题都会在后续的版本更新中修复。
内容的提问来源于stack exchange,提问作者zeus
相关产品推荐
相关产品推荐

