考虑以下程序:
int i{0};
std::experimental::barrier b{2};
int main()
{
std::thread t0{[] {
b.arrive_and_wait();
std::cout << i << '\n';
}};
std::thread t1{[] {
i = 2;
b.arrive_and_wait();
}};
t0.join();
t1.join();
}
即使2
不是原子变量,该程序也能保证打印出i
吗?
根据cppreference:
对
arrive_and_wait
的调用与障碍完成阶段的开始同步。完成阶段的完成与调用返回的内容保持同步。对
arrive_and_drop
和arrive_and_wait
的调用永远不会彼此或相互引入数据争用。
这表明每个arrive_and_wait
调用上都有一个同步点。但是我不确定是否允许编译器对i
上的读/写操作重新排序,因为它是非原子的。
答案 0 :(得分:3)
根据我对std::barrier reference的理解(重点):
屏障具有完成阶段,一旦参与线程集中的所有线程到达同步点,该阶段便由参与线程之一执行。到达和等待调用和到达和下降调用与完成阶段的开始同步; 完成阶段的结束与被其完成阻止的所有呼叫的返回结果保持同步。
您可以假定在其他线程中的屏障之前所做的所有更改在其他线程中都是可见的,即使它们不是原子的也是如此。正如this reference指出的(我的重点):
在线程之间,如果满足以下任一条件,则在评估B之前发生一个线程间线程
1)A与B同步
2)A在B之前是依依顺序排列的
3)A与某些求值X同步,并且X在B之前被排序
4)A在某些求值X之前被排序,并且X线程间发生在B之前。
5)线程间发生在某些评估X之前,而X线程间发生在B之前。