c++ - atomic() 中的++、add 操作和 fetch_add() 有什么区别

标签 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;

} 

最佳答案

++cntcnt.fetch_add(1) 是真正的原子操作。一个线程被阻塞,而另一个线程读取、递增和更新值。因此,两条线不能踩到对方的脚趾。对cnt的访问是完全序列化的,最终结果如你所愿。

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

关于c++ - atomic() 中的++、add 操作和 fetch_add() 有什么区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52069803/

相关文章:

c++ - 调用函数来初始化构造函数列表中的类是否安全?

c++ - 如何在没有高 CPU 使用率的情况下在 OpenGL 游戏中正确渲染模型(带纹理的网格)?

c++ - ncurses new_menu 段错误

c++ - 在 Howard Hinnant 的 Date 库中获取毫秒舍入时间戳字符串的最佳方法是什么?

c++11 - 通过删除叶子来制作 boost 图的子图

c++ - Boost.test找不到main

c++ - 打印到 cout 时舍入双数

c++ - 每当我更改 QTableWidget.item(row, col) 时发生访问冲突

关于继承成员地址的 C++ 标准

c++ - 在 C++ 中,按序号链接和按名称链接是什么意思?