void foo(volatile int& a, volatile int& b, bool threadOne) {
if (threadOne) {
//EDIT: switched the following two lines
b = 10;
a = 5;
} else {
while(a == 0);
cout << a << b;
}
}
//somewhere else
int a = 0;
int b = 0;
std::thread th1(foo, a, b, true);
std::thread th2(foo, a, b, false);
这在x86上是否安全,即根据c ++标准和x86参考的每个合法交错指令都将打印“510”?我的假设是它实际上是安全的。
答案 0 :(得分:5)
§1.10[intro.multithread](引用N4140):
6两个表达式评估冲突如果其中一个修改了a 内存位置(1.7)和另一个访问或修改它 记忆位置。
23如果
,两个动作可能并发
- 它们由不同的线程执行,或
- 它们没有排序,至少有一个是由信号处理程序执行的。
如果程序包含两个,则程序的执行包含数据竞争 潜在的并发冲突行为,其中至少有一个是 不是原子的,也没有发生在另一个之外,除了 下面描述的信号处理程序的特殊情况。任何这样的数据竞争 导致未定义的行为。
您的一个线程从a
读取,另一个线程从a
读取,两者都不是原子的,并且这两个潜在的并发冲突操作都不会在另一个之前发生。因此,您有数据竞争和未定义的行为。
答案 1 :(得分:4)
tl; dr 不,不,不,一千次没有。
就C ++ 11标准而言,程序具有未定义的行为,因为它具有数据争用(a
由并发执行读取和写入而不同步。所以不,它不会总是打印510. volatile
对此没有任何影响,它并不意味着C#和Java中的volatile
意味着什么。
我也怀疑(但不能充满信心地断言)独立地,x86芯片也可以破坏这个程序,尽管可能不是由于交错。然而,
a
的新值可能会在b
的新值变为可见之前生效(因为没有内存栅栏阻止芯片重新排序写入)。你正在玩火。没有充分理由启动,条件变量很便宜。如果预期的延迟足够小,条件变量不便宜,那么自旋锁(具有适当的同步,即原子)将是便宜的。