Gtr*_*rex 0 c++ c++11 stdatomic
我想知道我们是否只是进行加载和存储之间是否有任何std::atomic<int>不同int。我不关心内存顺序。例如考虑下面的代码
int x{1};
void f(int myid) {
while(1){
while(x!= myid){}
//cout<<"thread : "<< myid<<"\n";
//this_thread::sleep_for(std::chrono::duration(3s));
x = (x % 3) + 1;
}
}
int main(){
thread x[3];
for(int i=0;i<3;i++){
x[i] = thread(f,i+1);
}
for(int i=0;i<3;i++){
x[i].join();
}
}
Run Code Online (Sandbox Code Playgroud)
现在输出(如果取消注释 cout)将是
线程:1
螺纹数:2
螺纹数:3
...
int x我想知道更改为有什么好处吗atomic<int> x?
考虑你的代码:
void f(int myid) {
while(1){
while(x!= myid){}
//cout<<"thread : "<< myid<<"\n";
//this_thread::sleep_for(std::chrono::duration(3s));
x = (x % 3) + 1;
}
}
Run Code Online (Sandbox Code Playgroud)
如果程序没有未定义的行为,那么您可以预期,当被f调用时,x将从堆栈中至少读取一次,但是完成此操作后,编译器没有理由认为任何更改都会在x函数外部发生,或者x函数内所做的任何更改都需要在函数外部可见,直到函数返回后,因此它有权读x入 CPU 寄存器,继续查看相同的寄存器值并将其进行比较myid- 这意味着它将要么立即通过,要么永远被卡住。
然后,编译器可以假设它们会取得进展(请参阅 C++ 标准中的前进进展),因此它们可以得出结论,因为如果x != myid,x不可能等于,它们永远不会取得进展myid,并删除内部while循环。类似地,简化为寄存器的外循环while (1) x = (x % 3) + 1;不会x取得进展,也可以被消除。或者,编译器可以离开循环,但删除 上看似毫无意义的操作x。
将代码放入在线Godbolt编译器资源管理器中,并在-O3优化时使用GCC trunk进行编译,f(int)代码为:
f(int):
.L2:
jmp .L2
Run Code Online (Sandbox Code Playgroud)
如果你使x原子化,那么编译器不能在访问/修改寄存器时简单地使用它,并假设在函数返回之前有一个很好的时间来更新它。它实际上必须修改内存中的变量并传播该更改,以便其他线程可以读取更新的值。
| 归档时间: |
|
| 查看次数: |
1362 次 |
| 最近记录: |