【发布时间】:2013-06-18 20:17:34
【问题描述】:
我正在寻找 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 在“如何使用“良性”数据竞争错误编译程序”中所指出的那样(变量名称已针对上面的 sn-p 进行了相应调整):
如果编译器决定它需要在两个测试之间溢出包含 local_copy_of_shared_var 的寄存器,它可能会决定避免存储该值(毕竟它只是 shared_var 的副本),而是简单地重新读取涉及 local_copy_of_shared_var 的第二次比较的 shared_var 值。
[...] 核心问题源于编译器利用了变量值在没有显式赋值的情况下无法异步更改的假设。如果在我们的设置中语言规范不允许数据竞争,那么这种假设是完全合理的。在没有数据竞争的情况下,不可能进行这样的异步更改
现在,由于原子(使用默认的 seq_cst 内存排序)应该保证没有数据竞争,并且因为它们是编译器的“提示”,即不同线程之间存在此类变量的交互,有人可能会争辩说使用原子在前面的 sn-p 中将阻止编译器从 shared_var 插入此类“重新读取”,而是将 local_copy_of_shared_var 视为“一次性”快照,从而避免这两个测试?
我认为我的推理有问题,因为在常识的驱动下,我不会认为仅在这里使用原子就可以保证编译器会采取措施,以便 local_copy_of_shared_var在两次测试之间不会更新。 另一方面,正如 Herb 在他的演讲中所说,内存模型现在保证编译器在使用原子时不应该添加任何虚假的内存操作,这(将这种情况视为虚假读取)再次表明这个例子现在是“安全的”。 我很困惑,想听听社区的意见,如果我的推理有问题,我可能会得到纠正。
【问题讨论】:
标签: c++ c++11 atomic memory-model