++,添加操作和原子()中的fetch_add()有什么区别

Alo*_*lok 23 c++ c++11

我多次运行以下代码,但为什么前缀增量的结果,fetch_add()显示正确的结果,而使用添加操作(+),它会输出错误的结果?

#include <iostream>
#include <mutex>
#include <future>
using namespace std;
atomic <int> cnt (0);
void fun()
{
    for(int i =0; i <10000000 ; ++i)
    {
       //++cnt; // print the correct result 20000000 
       //cnt = cnt+1; // print wrong result, arbitrary numbers 
       cnt.fetch_add(1); //  print the correct result 20000000 
    }
}
int main()
{
    auto fut1 = async(std::launch::async, fun);
    auto fut2 = async(std::launch::async, fun);
    fut1.get();
    fut2.get();
    cout << "value of cnt: "<<cnt <<endl;

} 
Run Code Online (Sandbox Code Playgroud)

Rem*_*eau 29

++cnt并且cnt.fetch_add(1)是真正的原子操作.一个线程被阻塞,而另一个线程读取,递增并更新该值.因此,两个线程不能互相踩到脚趾.访问权限cnt是完全序列化的,最终结果如您所料.

cnt = cnt+1;不是完全原子的.它涉及三个独立的操作,其中只有两个是原子的,但一个不是.当一个线程以原子方式读取当前值cnt并在本地复制它时,另一个线程不再被阻塞,并且可以cnt在该副本递增时随意自由修改.然后,将递增的副本分配回cnt原子,但如果cnt已被另一个线程修改,则将分配过时的值.所以最终结果是随机的而不是你所期望的.

  • 根据标准 `cnt.fetch_add(1)` 等价于 `cnt++`。 (2认同)

tas*_*oor 10

cnt = cnt+1

这不是原子操作.这首先cnt在一个原子操作中加载,然后进行添加并最终将结果存储在另一个原子操作中.但是,加载后可以更改该值,最终存储可能会覆盖该值,从而导致错误的最终结果.

另外两个是原子操作,因此避免了这种竞争条件.

请注意,运算符++, --, +=, -=, &=, |=, ^=被重载std::atomic以提供原子操作.