我正在寻找第二次 Herb 精彩的“原子武器”演讲,我试图围绕经历整个内存模型/顺序一致性故事的概念来思考。现在有一件事在概念层面困扰着我。谈话的要点是,通过使用原子,我们可以“提示”编译器关于线程之间的交互,否则编译器将无法检测到。
所以我开始担心以下情况:
int local_copy_of_shared_var = shared_var;
if (local_copy_of_shared_var > some_threshold)
{
DoSomething();
}
... Do some work
if (local_copy_of_shared_var > some_threshold)
{
DoSomethingElse();
}
在这种情况下,正如 Hans Bohem 在“如何使用“良性”数据竞争错误编译程序”中所指出的那样(变量名称已针对上面的代码片段进行了相应调整):
如果编译器决定它需要在两个测试之间溢出包含 local_copy_of_shared_var 的寄存器,它可能会决定避免存储该值(毕竟它只是 shared_var 的副本),而是简单地重新读取 shared_var 的值对于涉及 local_copy_of_shared_var 的第二个比较。
[...] 核心问题源于编译器利用了变量值在没有显式赋值的情况下无法异步更改的假设。如果在我们的设置中语言规范不允许数据竞争,那么这种假设是完全合理的。在没有数据竞争的情况下,不可能进行这样的异步更改
现在,由于原子(使用默认的 seq_cst 内存排序)应该保证没有数据竞争,并且因为它们是编译器的“提示”,即不同线程之间存在此类变量的交互,有人可能会争辩说在前面使用原子片段会阻止编译器从shared_var插入此类“重新读取” ,而是将local_copy_of_shared_var视为“一次性”快照,以避免两个测试之间的不一致?
我认为我的推理有问题,因为在常识的驱动下,我不会认为仅在此处使用原子可以保证编译器将采取措施,以使local_copy_of_shared_var在两次测试之间不会得到更新。另一方面,正如 Herb 在他的演讲中所说,内存模型现在保证编译器在使用原子时不应该添加任何虚假的内存操作,这(将这种情况视为虚假读取)再次表明这个例子现在是“安全的”。我很困惑,想听听社区的意见,如果我的推理中有一些错误,我可能会得到纠正。