如何解决atomic <int>和int之间的区别
我想知道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
更改为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
进行比较-这意味着它要么立即通过,要么永远卡住。
然后,允许编译器假定他们会取得进展(请参阅C ++标准中的Forward Progress),因此他们可以得出结论,因为如果x != myid
,x
可以t可能等于myid
,并删除内部的while
循环。同样,简化为while (1) x = (x % 3) + 1;
的外部循环(其中x
可能是寄存器)不会取得进展,也可以消除。或者,编译器可以退出循环,但删除x
上看似毫无意义的操作。
将您的代码放入在线Godbolt编译器浏览器中,并以-O3
优化的GCC主干进行编译,f(int)代码为:
f(int):
.L2:
jmp .L2
如果使x
原子化,则编译器不能在访问/修改寄存器时简单地使用寄存器,并假定在函数返回之前会有适当的时间进行更新。实际上,它将不得不修改内存中的变量并传播更改,以便其他线程可以读取更新后的值。
我想知道将int x更改为atomic x是否有好处?
你可以这么说。在您的示例中将<button class="grey" value="ac">ac</button>
<button class="grey" value="+">+</button>
<button class="grey" value="-">-</button>
<button class="grey" value="%">%</button>
<button class="coral" value="➗">➗</button>
<button class="dark" value="7">7</button>
<button class="dark" value="8">8</button>
<button class="dark" value="9">9</button>
<button class="coral" value="X">X</button>
<button class="dark" value="4">4</button>
<button class="dark" value="5">5</button>
<button class="dark" value="6">6</button>
<button class="coral" value="minus">-</button>
<button class="dark" value="1">1</button>
<button class="dark" value="2">2</button>
<button class="dark" value="3">3</button>
<button class="coral" value="add">+</button>
<button class="zero" value="0">0</button>
<button class="dark" value=".">.</button>
<button class="coral" value="equal">=</button>
转换为int
会将程序从不正确变为正确(*)。
同时从多个线程访问相同的atomic<int>
(没有任何形式的访问同步)是未定义行为。
*)好吧,该程序可能仍然不正确,但至少可以避免该特定问题。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。