当前位置: 首页 > article >正文

std::memory_order 多线程编程中的内存顺序

std::memory_order 是 C++11 引入的一个枚举,用于控制多线程编程中的内存顺序。它定义了在原子操作中对内存的可见性和排序的要求。它在 C++ 标准库的 <atomic> 头文件中,配合原子类型和操作(如 std::atomicstd::atomic_flag)使用,以确保不同线程之间的数据同步。

下面是 std::memory_order 的每个成员及其作用:

1. std::memory_order_relaxed

  • 作用:执行无序原子操作,不提供顺序一致性保证。不同线程之间的操作可以乱序,适用于对性能要求高且数据同步要求低的场景。
  • 特点:只保证当前原子变量的操作是原子的,但不保证该操作与其他内存操作的相对顺序。
  • 适用场景:计数器、统计等无需严格同步的数据结构。

2. std::memory_order_consume

  • 作用:确保当前线程中对原子变量的操作和之后的读操作有顺序关系,但不保证写操作的顺序。
  • 特点:在某些特定平台上能比 memory_order_acquire 更高效(例如 ARM),但支持较差,通常会被编译器提升为 memory_order_acquire
  • 适用场景:不常用,通常用 memory_order_acquire 替代。

3. std::memory_order_acquire

  • 作用:获取同步,确保在该线程中,所有在此原子操作之前的内存写入对后续的读操作可见。
  • 特点:防止在获取操作后发生的读写操作被重排序到获取操作之前。
  • 适用场景:适合读操作,例如在读取一个共享变量时,需要确保读取的内容是最新的。

4. std::memory_order_release

  • 作用:释放同步,确保在该线程中,所有在此原子操作之前的内存写入对其他线程可见。
  • 特点:防止在释放操作之前的写入操作被重排序到释放操作之后。
  • 适用场景:适合写操作,通常在向其他线程发布信息或更新状态时使用。

5. std::memory_order_acq_rel

  • 作用:同时包含获取和释放语义,用于读写操作,确保此线程之前的所有写操作可见,之后的所有读操作会看到更新。
  • 特点:读写操作均同步,防止操作的重排序。
  • 适用场景:适合同时包含读取和写入的操作,常用于读-修改-写的操作中。

6. std::memory_order_seq_cst(Sequentially Consistent)

  • 作用:顺序一致性,最强的内存顺序保证,确保所有的原子操作在全局顺序上是唯一的。
  • 特点:确保线程间的操作严格按顺序发生,所有线程都看到一致的内存修改顺序。
  • 适用场景:适合对内存顺序要求严格的场景,但性能可能较低。标准库中的原子操作默认使用此顺序。

总结

Memory Order作用适用场景
memory_order_relaxed不保证内存顺序,仅确保原子性无需同步的简单计数操作
memory_order_consume仅确保后续读操作的顺序关系很少使用,通常用 acquire 替代
memory_order_acquire确保获取操作前的写操作不会重排,适合读操作读取共享数据,确保读取的是最新数据
memory_order_release确保释放操作后的写操作不会重排,适合写操作发布信息或更新状态
memory_order_acq_rel读写均同步,防止重排读-修改-写的操作
memory_order_seq_cst全局唯一顺序,最严格的内存保证对顺序要求严格的操作

示例

以下是一个简单例子,展示如何使用 memory_order_releasememory_order_acquire 来实现同步:

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

std::atomic<bool> ready(false);
std::atomic<int> data(0);

void producer() {
    data.store(42, std::memory_order_relaxed);  // 写入数据
    ready.store(true, std::memory_order_release);  // 发布信息
}

void consumer() {
    while (!ready.load(std::memory_order_acquire)) {  // 等待信息发布
        // busy-wait
    }
    std::cout << "Data: " << data.load(std::memory_order_relaxed) << std::endl;  // 读取数据
}

int main() {
    std::thread t1(producer);
    std::thread t2(consumer);

    t1.join();
    t2.join();

    return 0;
}

在此代码中:

  • producer 线程先写入数据,然后发布 ready 状态,使用 memory_order_release 确保 data 的写入在 ready 状态更新之前完成。
  • consumer 线程使用 memory_order_acquire 加载 ready,以确保读取到 true 状态时,data 中的值已经更新。

http://www.kler.cn/a/392878.html

相关文章:

  • 大数据开发面试宝典
  • MacOS 本地生成SSH key并关联Github
  • 【QT】QSS
  • 算法——移除链表元素(leetcode203)
  • 时序数据库TimescaleDB安装部署以及常见使用
  • k8s集群安装(kubeadm)
  • 【C++】list 与 string 基础与实现字符串操作
  • 玩转ChatGPT:文献阅读 v2.0
  • FPGA学习笔记#4 Vitis HLS 入门的第一个工程
  • 人工智能理论之opencv图像预处理、数据库、GUI布局的综合应用(图像预处理版块)
  • 【GPT使用技巧】用AI出一门课
  • 阿里云智能语音交互产品试用,基于语音识别、语音合成、自然语言理解
  • 将Docker中nginx静态资源目录映射到宿主机的某个目录及配置文件映射到宿主机
  • 大语言模型LLM综述
  • day13|C++重难点之 静态变量、全局变量、局部变量的区别,在内存上是怎么分布的、指针和引用的区别、C++内存分区
  • 想让三维模型与实时视频融合?这款软件值得一试
  • 大模型落地之ollama控制设备
  • 【MySQL】explain之type类型
  • Rust学习(四):作用域、所有权和生命周期:
  • MATLAB 使用教程 —— 命令窗口输入命令,工作区显示变量
  • Halcon深度学习之全局上下文异常值模型
  • 使用热冻结数据层生命周期优化在 Elastic Cloud 中存储日志的成本
  • python如何使用Rabbitmq
  • 从入门到了解C++系列-----内存管理 + 初步了解模板
  • CSS Modules是什么?
  • 【软件开发】Spring 面向切面编程(头歌作业)