详解c++ atomic原子编程中的Memory Order

当使用C++中的原子类型进行编程时,需要指定原子操作的内存顺序(Memory Order),以保证多线程下的正确性和一致性。

C++中原子操作的内存顺序一共有4种:

  1. memory_order_relaxed:最轻松的内存顺序,不会保证原子操作的顺序,也不保证操作的内存可见性。当我们要进行仅仅是读写共享内存而无需考虑同步问题的操作时,可以使用memory_order_relaxed。

示例1:使用relaxed内存顺序进行无锁统计

#include <iostream>
#include <thread>
#include <atomic>

int main() {
    std::atomic<int> counter(0);
    std::thread thread1([&counter]() {
       for (int i = 0; i < 100000; i++) {
           counter.fetch_add(1, std::memory_order_relaxed);
       }
    });

    std::thread thread2([&counter]() {
        for (int i = 0; i < 100000; i++) {
            counter.fetch_add(1, std::memory_order_relaxed);
        }
    });

    thread1.join();
    thread2.join();
    std::cout << counter << std::endl;
    return 0;
}

在这个示例中,我们使用了memory_order_relaxed内存顺序进行了两次原子操作,每次都是将counter原子变量加1。由于C++标准未规定内存操作的执行顺序以及内存可见性,所以在不同的平台和不同的编译器下,结果可能不同。但是在本示例中,多线程下的结果符合预期。

  1. memory_order_acquire:当一个线程使用memory_order_acquire方式读取一个原子变量时,它自己的所有后续操作都不能在此之前执行,以此保证前面的读取的值是最新的。

示例2:使用acquire-read和release-write解决多线程下的生产消费模型

#include <iostream>
#include <thread>
#include <atomic>
#include <vector>

using namespace std;

vector<int> pool;
atomic<int> pool_index(0);

void producer() {
    for (int i = 0; i < 100000; i++) {
        int index = pool_index.fetch_add(1, std::memory_order_relaxed);
        pool[index] = i;
        // 发布对第index个元素的写操作
        atomic_thread_fence(std::memory_order_release);
    }
}

void consumer() {
    while (true) {
        int index = pool_index.fetch_sub(1, std::memory_order_acquire);
        // 加载第index个元素的值
        atomic_thread_fence(std::memory_order_acquire);
        if (index <= 0) {
            // 如果生产者已经停止了,则退出消费线程
            break;
        }
        cout << "consume: " << pool[index - 1] << endl;
    }
}

int main() {
    pool.resize(100000);
    thread t1(producer);
    thread t2(consumer);
    thread t3(consumer);
    t1.join();
    pool_index.store(0); // 停止生产者
    t2.join();
    t3.join();
    return 0;
}

在本示例中,我们通过使用acquire读和release写操作,避免了内存可见性和顺序的问题,从而实现了多个生产者和多个消费者协同工作的生产消费模型。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解c++ atomic原子编程中的Memory Order - Python技术站

(0)
上一篇 2023年5月23日
下一篇 2023年5月23日

相关文章

  • C语言 break语句

    C语言break语句使用攻略 break语句是C语言中的一种分支语句,用于跳出当前的循环语句或switch语句。本文将详细介绍break语句的使用方法和注意事项。 break语句的基本语法 C语言中break语句的基本语法如下: break; break语句只是一个完整的语句,它可以被任何一个循环语句或switch语句所包含。当执行到break语句时,程序将…

    C 2023年5月9日
    00
  • 如何用C语言添加矩阵

    添加矩阵是C语言中常见的任务之一。以下是一些基本的步骤: 1. 定义矩阵 在C语言中,可以使用二维数组来定义矩阵。例如,以下代码定义了一个3×3的矩阵: int matrix[3][3] = { {1,2,3}, {4,5,6}, {7,8,9} }; 2. 显示矩阵 可以使用循环来遍历矩阵中的所有元素,并将它们打印出来。例如,以下代码使用嵌套循环来遍历矩阵…

    C 2023年5月9日
    00
  • C语言实现考试报名管理系统

    C语言实现考试报名管理系统攻略 系统介绍: 本系统使用C语言编写,实现了考试报名管理系统,可以方便地管理考试的报名、查询与统计工作。 系统功能: 学生信息管理:系统中可以管理考生信息,包括学生姓名、学号、报考考试、成绩等信息。 考试报名:考生可以通过登录系统进行报名。 考试查询:考生和管理员根据个人信息可以查询自己或其他考生的成绩,并且管理员可以查看全体考生…

    C 2023年5月23日
    00
  • 探究一下C语言生成随机数的奥秘

    下面是关于“探究一下C语言生成随机数的奥秘”的完整攻略。 1. 引言 生成随机数在程序设计和数据分析过程中都是非常重要的一步。C语言中提供了多种方法来生成随机数,其中最常见的是使用stdlib.h库函数中的rand()函数。本文将对rand()函数进行详细介绍,并探究其生成随机数的奥秘。 2. rand()函数的使用 rand()函数是stdlib.h库中的…

    C 2023年5月22日
    00
  • centos网络配置方法(手动设置,自动获取)

    以下是详细的“CentOS网络配置方法”的攻略。 CentOS网络配置方法 CentOS是一种常用的Linux操作系统,网络配置是使用CentOS时必不可少的部分。这里我们将介绍手动设置和自动获取IP地址的两种方法。 注意:在进行下列操作之前,请确保您具有管理员权限。 手动设置IP地址 1.打开终端,输入下列命令来打开“网络管理器”的图形化界面: nm-co…

    C 2023年5月22日
    00
  • ps中怎么制作水火交融的字体效果?

    要制作水火交融的字体效果,可以使用Photoshop中的图层样式,具体步骤如下: 创建文字图层 在Photoshop中创建一个新的文档,然后选择文字工具在文档中添加一个文本。可以选择任何字体、任何颜色的文本,具体根据个人需要来定。 添加渐变图层样式 在图层面板中,选择文本图层。然后在图层面板顶部的图层样式(fx)图标上点击鼠标右键,选择“渐变叠加”选项,在弹…

    C 2023年5月23日
    00
  • C++实现算法两个数字相加详解

    C++实现算法两个数字相加详解 在C++中,实现两个数字相加的算法可以使用基本的加法运算符和关键字。以下是实现该算法的示例方法。 实现步骤 声明两个数字变量 a 和 b。 将这些变量的值设置为所需的数字。 使用加法运算符将这些数字相加,将结果存储在另一个变量中,命名为 result。 将结果打印到控制台。 下面是示例代码 int a = 20; int b …

    C 2023年5月23日
    00
  • c语言实现的货物管理系统实例代码(增加删除 查找货物信息等功能)

    一、简介 货物管理系统可以帮助企业更好地管理其货品,是一套非常实用的管理系统。本文将介绍使用c语言实现的一套货物管理系统,包括增加、删除、查找货物信息等功能。 二、实现步骤 设计数据结构 首先,我们需要设计合适的数据结构用于存储货物信息。可以使用结构体来定义货物信息,例如: struct goods { int id; char name[50]; int …

    C 2023年5月23日
    00
合作推广
合作推广
分享本页
返回顶部