浅析C++ atomic 和 memory ordering

浅析C++ atomic 和 memory ordering

简介

C++11 中引入了一个新的原子类型 —— std::atomic,用以在多线程环境中实现原子操作。同时,它也提供了 Memory Ordering 来确保原子操作的顺序性。本文将从理论和实践角度浅析 C++ atomic 和 memory ordering。

原子操作

原子操作是指一个操作要么全部完成,要么全部不完成,没有中间状态。例如对于下面的代码:

int i = 0;
i++;

在单线程环境中,这个代码很简单,i 的值将会被增加 1。但是在多线程环境中,如果两个线程同时执行上述代码中的 i++ 操作,由于没有对 i 进行原子化保护,最终 i 的值可能会小于预期的值。

C++11 中提供了 std::atomic 的数据类型,用以实现原子操作。std::atomic 是一种特殊的数据类型,它提供了一些函数来实现原子化操作,确保它们是以原子方式进行的。例如:

#include <atomic>

std::atomic<int> i(0);
i++;

上述代码实现了对 i 的原子增加操作,任意两个线程并发执行该操作也不会导致结果不正确。

除了原子化操作之外,std::atomic 还支持 Load 和 Store 操作。Load 操作从内存中读取数据,而 Store 操作则写入数据。

std::atomic<int> i(0);
int j = i.load();
i.store(1);

在上述代码中,i.load() 会将当前存储在 i 中的值读入 j 中,而 i.store(1) 则会将 1 写入 i 中。

内存顺序

在多线程环境中,原子操作的顺序性是需要被保证的。为了保证原子操作的顺序性,C++11 提供了 Memory Ordering 的机制,即内存顺序。

内存顺序是指代码中各个线程对 Memory Ordering 的要求,以及在应用程序中对信息进行同步的一个机制。

std::memory_order 是一个枚举类型,它提供了多种内存序,如 std::memory_order_relaxedstd::memory_order_seq_cst 等。

relaxed 内存序

std::memory_order_relaxed 表示没有任何顺序约束,可以使用最松散的约束来实现最高的性能。但是需要注意的是,使用 relaxed 内存序可能导致编写的代码在不同线程中表现出不同的行为。

下面是一个例子:

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

using namespace std;

atomic<int> x(0), y(0);
int r1 = 0, r2 = 0;

void write_x()
{
    x.store(1, memory_order_relaxed);
    r1 = y.load(memory_order_relaxed);
}

void write_y()
{
    y.store(1, memory_order_relaxed);
    r2 = x.load(memory_order_relaxed);
}

int main()
{
    thread a(write_x);
    thread b(write_y);
    a.join();
    b.join();
    cout << "r1: " << r1 << ", r2: " << r2 << endl;
    return 0;
}

在该例子中,线程 a 中的 x.store(1, memory_order_relaxed) 和线程 b 中的 y.store(1, memory_order_relaxed) 在执行时都是用 relaxed 内存序进行的。因此,二者之间的顺序在不同的运行环境中是无法保证的,即可能先执行 a,也可能先执行 b,因而 r1 和 r2 的值都有可能输出 0,都有可能输出 1,还可能输出 0 和 1。

release-acquire 内存序

std::memory_order_releasestd::memory_order_acquire 是针对 release 和 acquire 操作的 Memory Ordering 类型。

release 操作用于将本线程内存中的一个值写回到主存中,并发出信号禁止 CPU 将这些 write 操作放入到 CPU 内存队列中。它与 acquire 操作组合起来,能够实现同步传递的过程。

acquire 操作用于将内存从主存中读入到 CPU 内部缓存中,并等待前面的 release 操作完成后才进行操作。

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

using namespace std;

atomic<int> x;
atomic<int> y;

void write_x()
{
    x.store(1, std::memory_order_release);
}

void write_y()
{
    while (y.load(std::memory_order_acquire) != 1);
    cout << "y is 1" << endl;
}

int main()
{
    thread a(write_x);
    thread b(write_y);
    a.join();
    b.join();
    return 0;
}

在该例子中,线程 a 首先执行了 x.store(1, std::memory_order_release) 来写入 x 的值,该操作使用 release 内存序。线程 b 执行了 y.load(std::memory_order_acquire) 来读取 y 的值,当 y 的值为 1 时,程序输出 "y is 1"。该操作使用 acquire 内存序。

通过 release 和 acquire 操作,线程 b 可以正确地读取到线程 a 中写入的 x 的值,并做出相应的行动。

结论

C++11 提供了原子类型 std::atomic 来确保在多线程环境中的原子操作,并提供了内存顺序机制来保证原子操作的顺序性。在使用时需要根据具体情况进行选择。

参考资料

  1. C++11 标准 - 29. Lock-free property
  2. C++11并发编程:原子操作和内存序

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:浅析C++ atomic 和 memory ordering - Python技术站

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

相关文章

  • Win10提示错误代码 0xc000012F(坏图像)怎么办?

    首先,针对Win10提示错误代码 0xc000012F(坏图像),我们可以采取以下几个步骤进行处理: 确认错误类型 在处理问题之前,我们需要明确错误类型。针对这个错误代码,我们可以初步推断是系统文件损坏导致,因此我们可以采取以下思路进行处理。 运行磁盘扫描 在确认了错误类型之后,我们可以通过运行磁盘扫描,检查系统文件是否存在问题。具体的步骤如下: 打开“此电…

    C 2023年5月23日
    00
  • C#实现生成所有不重复的组合功能示例

    生成所有不重复的组合是一项常见的算法问题,可以使用C#编程语言轻松实现。下面是一个完整的攻略: 1. 程序实现思路 生成所有不重复的组合功能的实现思路如下: 创建一个长度为n的数组,数组中存储n个不同的元素。 从数组中选出其中的k个元素,形成一个组合。 从数组中选取下一个元素,生成下一个组合。 重复上述步骤,直到所有组合都被生成。 2. 实现代码 下面是使用…

    C 2023年5月22日
    00
  • 解析C++编程中的bad_cast异常

    下面是我为您提供的“解析C++编程中的bad_cast异常”的完整攻略。 什么是bad_cast异常 bad_cast异常是C++类型转换异常中的一种,其发生的原因是当使用dynamic_cast来进行指针或引用的类型转换时,如果该转换不合法,就会抛出bad_cast异常。 如何避免bad_cast异常 避免bad_cast异常的方法有几种: 使用stati…

    C 2023年5月23日
    00
  • mysql 如何使用JSON_EXTRACT() 取json值

    当mysql存储JSON格式的数据时,我们需要对JSON进行提取。MySQL 5.7版本以上,提供了JSON_EXTRACT()函数来实现从JSON中提取值。 JSON_EXTRACT()函数的语法 JSON_EXTRACT(json_path) json_path为JSON路径参数,返回该路径下的JSON值。 示例1 已知json字段’data’的值为: …

    C 2023年5月23日
    00
  • C++实现图书馆管理系统

    C++实现图书馆管理系统 概述 图书馆管理系统是一种基于计算机技术的,将各种机械设备取代,并能够更好地服务大众的管理系统。其原理是以计算机为核心,采用自动化技术,计算机网络技术,数据采集技术等先进技术对图书馆藏书、读者、借还书等活动进行管理。 使用C++编程语言进行开发,能够使用面向对象的编程技术,使得代码结构清晰,易于维护和扩展。在此,将介绍如何使用C++…

    C 2023年5月23日
    00
  • 深入解析Python编程中JSON模块的使用

    深入解析Python编程中JSON模块的使用 什么是JSON JSON全称为JavaScript Object Notation,是一种轻量级的数据交换格式,易于阅读和编写,也易于机器解析和生成。JSON数据格式能够表示数值、字符串、布尔值、对象、数组等类型的数据。它由键值对组成,常用于Web应用程序中的数据传输。 为什么要使用JSON 由于Web应用程序越…

    C 2023年5月23日
    00
  • VSCode断点调试CMake工程项目的实现步骤

    以下是详细讲解“VSCode断点调试CMake工程项目的实现步骤”的完整攻略。 1. 安装必要的插件 在使用VSCode进行CMake项目的断点调试,我们需要安装一些必要的插件。这些插件包括: C/C++插件 CMake工具插件 Debugger for gdb插件 在VSCode中打开扩展选项卡,搜索并安装上述插件。 2. 配置工程项目 在开始断点调试前,…

    C 2023年5月23日
    00
  • C++实现多源最短路径之Floyd算法示例

    C++实现多源最短路径之Floyd算法示例 多源最短路径问题是指在给定图中任意两个顶点之间的最短路径问题。Floyd算法是解决该问题的一种经典算法,效率较低,但实现简单。 本篇文章将详细讲解如何使用C++语言实现Floyd算法,主要包含以下内容: 代码实现 算法详解 示例说明 代码实现 #include<iostream> using names…

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