as-if规则是否阻止编译器重新排序对全局/成员变量的访问?

时间:2014-08-24 14:13:58

标签: c++ multithreading c++11

我正在研究编译器优化(特别是这里的指令重新排序)可能对多线程程序产生的影响。

假设我们有一个读者线程和一个写作者线程。

// Global shared data between threads
bool data;
bool flag = false;

// writer.cpp
void writer()
{
    data = true;  // (1)
    flag = true;  // (2)
}

// reader.cpp
void reader()
{
    if (flag)
    {
       count << data;
    }
}

是否符合C ++ 11标准的编译器重新排序指令(1)(2)

根据C ++“as-if”规则,转换不应该改变程序的可观察行为。显然,在编译编写器时,编译器通常无法确定重新排序(1)(2)是否会改变程序的可观察行为,因为dataflag是两个全局变量都可能影响另一个线程的可观察行为。

但它在此声明可以发生这种重新排序,请参阅memory ordering at compile time

那么我们需要(1)(2)之间的编译屏障吗? (我很清楚可能的CPU重新排序。这个问题仅适用于编译器重新排序)

2 个答案:

答案 0 :(得分:5)

绝对可能。编译器没有义务考虑对其他线程或硬件的副作用。

如果您使用volatile或同步(并且这两个可互换),编译器只会被考虑这一点。

标准内存模型称为SC-DRF,或顺序一致数据竞争免费。数据竞争正是您刚刚描述的情景 - 一个线程正在观察非同步变量而另一个正在变异。这是未定义的行为。实际上,标准明确地赋予编译器自由,假设没有其他线程或硬件正在读取非易失性非同步变量。编译器在此基础上进行优化是绝对合法的。

顺便说一句,那个链接有点废话。他的修复&#34;根本不解决任何问题。多线程代码唯一正确的解决方法是使用同步。

答案 1 :(得分:2)

你已经在一周半之前就comp.lang.c ++。问了这个问题,你得到了关于C ++ 11在单个线程中排序的要求与“for”之间关系的完整解释。发生在“线程之间的同步关系之前,这里:https://groups.google.com/forum/#!topic/comp.lang.c++.moderated/43_laZwVXYg

您不了解该回复的哪一部分,我们可以再试一次?