0

0

C++中的std::atomic怎么用?C++原子操作与无锁编程入门【多线程】

尼克

尼克

发布时间:2026-01-03 11:36:09

|

130人浏览过

|

来源于php中文网

原创

std::atomic 是 C++11 提供的无锁原子操作工具,用于多线程中安全读写简单变量(如 int、bool、指针),依赖 CPU 原子指令而非互斥锁;适用于计数器、状态标志、单生产者-单消费者队列索引等场景,但仅保证单操作原子性,不保障多变量逻辑一致性。

c++中的std::atomic怎么用?c++原子操作与无锁编程入门【多线程】

std::atomic 是 C++11 引入的核心工具,用来安全地在多线程中读写共享变量,避免数据竞争,是无锁编程的基础。它不依赖互斥锁(mutex),而是靠底层 CPU 指令(如 CAS、load/store with memory ordering)保证操作的原子性。

什么时候该用 std::atomic?

当你有一个简单变量(如 int、bool、指针),多个线程要并发读写,且操作本身足够“小”(比如加 1、赋值、比较交换),又不想上锁——这时候 atomic 就很合适。

  • 计数器(如引用计数、请求统计)
  • 状态标志(如 running = true/false)
  • 单生产者-单消费者队列中的头尾索引
  • 实现自旋锁、信号量等基础同步原语

⚠️ 注意:atomic 不等于“万能线程安全”。它只保单个操作原子,不保多个 atomic 变量之间的逻辑一致性。比如“先读 A 再写 B”不是原子的,仍需额外同步。

基本用法:声明、读、写、修改

以 int 为例:

立即学习C++免费学习笔记(深入)”;

std::atomic counter{0};  // 初始化为 0

counter.store(42);           // 原子写(等价于 counter = 42)
int x = counter.load();      // 原子读(等价于 x = counter)
int y = counter++;           // 原子后增(返回旧值)
counter.fetch_add(3);        // 原子加 3,返回旧值
counter.compare_exchange_weak(expected, desired); // CAS:若当前值==expected,则设为desired,返回true;否则把当前值写入expected,返回false

常见成员函数还有:exchange()(原子替换并返回旧值)、fetch_sub()fetch_and() 等。所有操作默认使用 memory_order_seq_cst(最强顺序,最安全也稍慢)。

内存序(memory order)怎么选?

内存序控制编译器重排和 CPU 乱序执行的边界,影响性能与正确性。初学者建议先全用默认(seq_cst),稳定后再优化。

Motiff
Motiff

Motiff是由猿辅导旗下的一款界面设计工具,定位为“AI时代设计工具”

下载
  • memory_order_relaxed:只保证原子性,不约束前后指令顺序。适合计数器、时间戳等无需同步语义的场景。
  • memory_order_acquire:用于读操作,保证它之后的读写不被重排到它前面(进入临界区)。
  • memory_order_release:用于写操作,保证它之前的读写不被重排到它后面(退出临界区)。
  • memory_order_acq_rel:读-修改-写操作(如 fetch_add)常用,兼具 acquire 和 release。
  • memory_order_seq_cst:全局顺序一致,所有线程看到的操作顺序相同。C++ 默认,最易理解。

例子:用 atomic 实现自旋锁

struct spinlock {
    std::atomic locked{false};
    void lock() {
        while (locked.exchange(true, std::memory_order_acquire)) {
            // 自旋等待
        }
    }
    void unlock() {
        locked.store(false, std::memory_order_release);
    }
};

注意事项和常见坑

不能对 atomic 对象取地址或 memcpy —— 它可能包含对齐填充或内部状态,行为未定义。

不支持浮点类型直接原子操作(C++20 起部分支持) —— 如需原子 float,可用 std::atomic + union 或 bit_cast 模拟(需谨慎处理 NaN/符号)。

结构体不能直接 atomic,除非是 trivially copyable 且满足对齐要求 —— 大多数自定义 struct 需用 mutex 保护,或用 std::atomic_ref(C++20)包装已存在变量。

compare_exchange_weak 可能虚假失败 —— 在循环中使用,不要假设失败就代表值变了。

基本上就这些。atomic 是无锁编程的起点,但不是终点。真正复杂的无锁数据结构(如无锁、队列)需要深入理解内存模型和算法设计。先从计数器、标志位练起,再逐步挑战 CAS 循环和 ABA 问题应对——不复杂但容易忽略细节。

相关专题

更多
css中float用法
css中float用法

css中float属性允许元素脱离文档流并沿其父元素边缘排列,用于创建并排列、对齐文本图像、浮动菜单边栏和重叠元素。想了解更多float的相关内容,可以阅读本专题下面的文章。

554

2024.04.28

C++中int、float和double的区别
C++中int、float和double的区别

本专题整合了c++中int和double的区别,阅读专题下面的文章了解更多详细内容。

95

2025.10.23

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

194

2025.06.09

golang结构体方法
golang结构体方法

本专题整合了golang结构体相关内容,请阅读专题下面的文章了解更多。

186

2025.07.04

c语言union的用法
c语言union的用法

c语言union的用法是一种特殊的数据类型,它允许在相同的内存位置存储不同的数据类型,union的使用可以帮助我们节省内存空间,并且可以方便地在不同的数据类型之间进行转换。使用union时需要注意对应的成员是有效的,并且只能同时访问一个成员。本专题为大家提供union相关的文章、下载、课程内容,供大家免费下载体验。

122

2023.09.27

c语言union的用法
c语言union的用法

c语言union的用法是一种特殊的数据类型,它允许在相同的内存位置存储不同的数据类型,union的使用可以帮助我们节省内存空间,并且可以方便地在不同的数据类型之间进行转换。使用union时需要注意对应的成员是有效的,并且只能同时访问一个成员。本专题为大家提供union相关的文章、下载、课程内容,供大家免费下载体验。

122

2023.09.27

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

313

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

522

2024.08.29

php源码安装教程大全
php源码安装教程大全

本专题整合了php源码安装教程,阅读专题下面的文章了解更多详细内容。

177

2025.12.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
React 教程
React 教程

共58课时 | 3.2万人学习

Pandas 教程
Pandas 教程

共15课时 | 0.9万人学习

ASP 教程
ASP 教程

共34课时 | 3.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号