我正在研究编译器优化(特别是此处的指令重新排序)可能对多线程程序产生的影响。
假设我们有一个读者线程和一个作者线程。
// 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”规则,转换不应改变程序的可观察行为。显然,在编译 writer 时,编译器通常不能确定重新排序 (1)
和 (2)
是否会改变程序的可观察行为,因为 data
和 flag
都是全局变量,可能会影响另一个线程的可观察行为。
但它在这里声明这种重新排序可能会发生,请参阅 memory ordering at compile time .
那么我们是否需要在 (1)
和 (2)
之间设置编译器屏障? (我很清楚可能的 CPU 重新排序。这个问题只针对编译器重新排序)
最佳答案
当然可以。编译器没有义务考虑对其他线程或硬件的副作用。
只有在您使用 volatile
或同步(这两者不可可互换)时,编译器才会被迫考虑这一点。
标准内存模型称为 SC-DRF,即无顺序一致数据竞争。数据竞争正是您刚刚描述的场景——一个线程正在观察非同步变量,而另一个线程正在改变它们。这是未定义的行为。实际上,该标准明确地赋予编译器自由假设没有其他线程或硬件正在读取非 volatile 非同步变量。编译器在此基础上进行优化是绝对合法的。
顺便说一句,那个链接有点垃圾。他的“修复”根本没有解决任何问题。多线程代码的唯一正确解决方法是使用同步。
关于c++ - as-if 规则是否会阻止编译器对全局/成员变量的访问进行重新排序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25472608/