std::atomic 是什么

std::atomic<T> 是 C++11 引入的原子模板类 ,头文件:#include <atomic>

原子:一个操作不可被打断,CPU 一次性完成,不会出现 "读到一半、写到一半" 的中间状态。专门用来做多线程之间共享变量的安全读写。

核心解决两大问题

  1. 竞态条件(数据撕裂) 普通变量多线程同时读写,有可能读到半截值(比如 32int,写了低 16 位还没写高 16 位,读线程就拿走了)。atomic 保证读写操作是完整的,不会读到半拉数据。
  2. 内存可见性(CPU 缓存 / 编译器优化) 多核 CPU 每个核心有独立缓存;编译器会把变量优化放到寄存器,不一定每次都读写内存。 普通 bool:主线程写flag=true,子线程可能一直读寄存器里旧的false,永远看不到更新。std::atomic自带内存屏障:强制读写直接同步到主内存,其他线程立刻看到最新值。

基础用法( std::atomic<bool>)

复制代码
std::atomic<bool> m_bThreadExit;
m_bThreadExit = false;  //赋值
m_bThreadExit = true;

while(!p->m_bThreadExit) //读取

✅ 读写不需要再加临界区 CCriticalSection。原子变量本身就是线程安全。

支持的基础类型

std::atomic<bool>、std::atomic<int>、std::atomic<unsigned int> 最常用。

不能随便放自定义类,一般只用基础类型。

常用成员函数

复制代码
std::atomic<bool> flag{false};

bool v = flag.load();   //读取,等价于 bool v = flag;
flag.store(true);       //写入,等价于 flag = true;

简写写法 flag=true / if(flag) 在工程里完全够用。

和 CCriticalSection(临界区)对比

  1. std::atomic
  • 适合:简单标记(bool、计数器这类简单变量)
  • 开销极小,无内核阻塞;纯用户态指令
  • 局限:只能保护单个变量,不能保护一段代码、多个变量
  1. CCriticalSection(临界区)
  • 适合:多变量、一段业务代码的互斥

  • 可以包裹一大段代码,锁期间别的线程阻塞等待

  • 开销比 atomic 大

  • m_bThreadExit:只是一个退出标记,用 std::atomic<bool>

  • m_iSaveSOE:配合一段业务逻辑,读写成对,用 CCriticalSection theApp.m_lockSoe

⚠️ 重要误区

  1. ❌ std::atomic不能替代临界区处理多变量事务 比如同时修改 A、B 两个变量,atomic 只能保证 A 自身原子、B 自身原子,不能保证 A 和 B 同时一起更新。这种场景必须临界区。

  2. ❌ atomic<bool> 只保证变量读写原子,不保护 if 里面后续代码

    if(flag)
    {
    //这里代码不再受atomic保护!
    }

判断完成之后 flag 立刻可能被别的线程修改,这是正常现象。

和 volatile 的区别(工控老项目常混淆)

复制代码
volatile bool flag;
  • volatile:只禁止编译器优化,每次强制读内存 ,不提供多核 CPU 缓存同步,多核环境有概率失效。
  • std::atomic:同时做到:禁止编译器优化 + CPU 缓存同步 + 操作原子。

所以 C++11 以后,多线程共享标记优先 atomic,volatile 只用于硬件寄存器访问。

举个简化示例,模拟的线程退出场景

复制代码
#include <atomic>
#include <windows.h>
#include <Afxwin.h>

std::atomic<bool> g_exit = false;

UINT ThreadFunc(LPVOID p)
{
    while(!g_exit)
    {
        Sleep(10);
        TRACE(_T("running\n"));
    }
    TRACE(_T("thread exit\n"));
    return 0;
}

主线程设置 g_exit=true; 子线程马上感知到并退出。

一句话总结

std::atomic<T> 就是多线程共享单个简单变量的轻量级线程安全包装,不用锁,保证变量读写完整、内存可见。 用来做线程退出标记,属于 atomic 最经典、最合适的使用场景。

相关推荐
2401_862880821 小时前
input 子系统框架 、platform 驱动框架
linux·驱动开发·嵌入式硬件
Liuqy-051 小时前
线程的互斥与同步机制——互斥锁、条件变量、无名信号量
linux·开发语言·线程·进程·条件变量·同步·互斥
十年磨一剑~1 小时前
LVDS 背光控制问题排查与 DTS 修正文档
linux·ubuntu
有毒的教程1 小时前
Linux底层存储路由配置
linux·运维·网络
日常筹谋记1 小时前
仓储监测无线化改造经验:明治无线组网方案与WL系列Master总站落地复盘
网络·网络协议
All for pursuit.1 小时前
【完结】LeetCodeHot100题 详细解题过程及代码汇总
数据结构·c++·算法·leetcode
瑞克-桑切斯2 小时前
2、Shell 条件语句
java·linux·服务器
Logic1012 小时前
C语言/数据结构位运算题解:异或XOR找出数轴移动中只出现一次的指令——只出现一次的数字
c语言·数据结构·数组·位运算·时间复杂度·算法题·异或性质