今天在维护之前的无锁容器的时候出现了一个很奇怪的bug,在C++20时可以正常使用,在C++17时就会出现异常,最终debug把问题定位并缩小在atomic的compare_exchange_strong中,但我发现了一件非常恐怖的事情,仿佛是我写代码经历了量子危机。
有以下代码:
#include <atomic>
#include<iostream>
using namespace std;
struct MyStruct {
int a;
double b;
};
int main() {
std::atomic<MyStruct> myAtomic{ MyStruct{1, 2.0} };
MyStruct expected{ 1, 2.0 };
MyStruct desired{ 2, 3.0 };
bool ok=myAtomic.compare_exchange_strong(expected, desired);
cout << ok << endl;
return 0;
}
运行上面一段代码,在肉眼观察下我们应该会推测应该会输出1,因为原子变量和预期值相等,交互应该会成功,但是奇怪的一幕出现了,我的Visual Studio C++17编译会输出0。嗯,我开始困惑,把编译器调回C++20,又正常输出1了。
后面我又把编译器调回了C++17 尝试找出问题所在,后面更恐怖的事情发生了,当我在compare_exchange_strong后面添加一句
cout << myAtomic.load().a << " " << myAtomic.load().b << endl;
恐怖的事情发生了,这个结果输出了2 3 \n 1 对,ok又变成了true,我甚至一度怀疑我眼花了,把这句又删除了,输出又变成了0,对ok又变成了false,难道我对这个原子变量是否进行观测还会还会影响compare_exchange_strong的执行?我一度又检测了代码的内存次序,强制调整成std::memory_order_seq_cst,问题依然如此。
好的,我甚至开始怀疑是不是编译时内存次序还有什么隐秘的问题,我把上面的观测代码放到输出ok后面,输出依然是1 \n 2 3 对,ok又变成true了,仿佛是量子力学的观察者效应。希望强者给我一些解答,这是否是VS C++17标准库的缺陷还是我的代码出现了什么问题?