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 最经典、最合适的使用场景。

相关推荐
乐维_lwops22 分钟前
案例解读:大型综合性科创产业园运维监控落地实践
运维·网络·人工智能·安全·it监控·国产运维智能体
GeW1 小时前
新质生产力Linux和数据库为啥这么关键
linux
Fuyo_11191 小时前
C++ 运行时多态与虚函数机制全面剖析【面试重点】
开发语言·c++·面试
§ꦿCFོ༉2 小时前
嵌入式八股—C语言入门学习(一)
c语言·编程语言·嵌入式八股文
番茄啊2 小时前
linux 开启xftp连接
linux·运维·服务器
CodeYp20192 小时前
第1讲:Linux 基础指令
linux·指令
m0_715674432 小时前
政务泛监测体系能力排行:AI 重塑监测边界,治理的颗粒度革命
大数据·网络·人工智能·安全·网络安全·政务
李松桃2 小时前
基于端口号的服务配置
linux·nginx-核心模块配置
AI 编程助手GPT3 小时前
curl 返回成功就能收文件?用本地 HTTP 验证错误页与超时
网络·网络协议·http
Chen_harmony3 小时前
七、STL与string类
开发语言·c++