c++ - 原子之间的区别和整数
问题描述
我想知道两者之间是否有任何不同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();
}
}
现在输出(如果您取消注释 cout)将是
主题:1
主题:2
主题:3
...
我想知道更改int x
to是否有任何好处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;
}
}
如果程序没有未定义的行为,那么您可以期望在f
调用x
时至少会从堆栈中读取一次,但是这样做后,编译器没有理由认为任何更改x
都会发生在函数之外,或者在函数返回之前,函数内所做的任何更改都x
需要在函数外可见,因此它有权读取x
CPU 寄存器,继续查看相同的寄存器值并将其与myid
- 这意味着它将要么立即通过,要么永远卡住。
x != myid
然后,允许编译器假设他们会取得进展(参见 C++ 标准中的 Forward Progress),因此他们可以得出结论,因为如果,x
不可能等于,他们将永远不会取得进展myid
,并删除内部while
循环。while (1) x = (x % 3) + 1;
同样,简化为可能是寄存器的外部循环x
- 没有取得进展,也可以被消除。或者,编译器可以退出循环,但删除对x
.
将您的代码放入在线 Godbolt 编译器资源管理器并在-O3
优化时使用 GCC 主干进行编译,f(int) 代码为:
f(int):
.L2:
jmp .L2
如果您使x
原子成为原子,那么编译器在访问/修改它时不能简单地使用寄存器,并假设在函数返回之前会有一个很好的时间来更新它。它实际上必须修改内存中的变量并传播该更改,以便其他线程可以读取更新的值。
推荐阅读
- java - 必须定义 GOOGLE_APPLICATION_CREDENTIALS 指向定义凭据的文件
- batch-file - 如何禁用批处理脚本中的输入?
- php - Laravel Action App\Http\Controllers\Admin\ConcursoController@store 未定义
- javascript - 将json对象转换为数组
- c# - 如何使用编码的 UI (C#) 处理多个 IE 浏览器实例
- templates - 如何使用 xslt 1.0 在输出中排除子节点?
- ios - UISearchBar 打开第二个 TableView 没有结果
- windows-services - 作为本地系统运行的 Windows 服务应该将私钥存储在文件系统中的什么位置?
- db2 - 在 Db2 中识别 UDF 内的模式
- javascript - 如何仅停止最后一个获取请求