c++ std::atomic如何保证原子性 c++ CAS操作原理【底层】
技术百科
穿越時空
发布时间:2026-01-01
浏览: 次 std::atomic的原子性由编译器生成特定CPU指令(如x86的lock、ARM的ldxr/stxr)与硬件共同实现,CAS是核心原语;compare_exchange_weak允许伪失败,compare_exchange_strong无伪失败;内存序控制可见性而非原子性。
std::atomic 的原子性不是靠 C++ 语言本身“保证”的,而是通过编译器生成特定的底层指令(如 x86 的 lock 前缀指令、ARM 的 ldxr/stxr 等)+ CPU 硬件支持共同实现的。CAS(Compare-And-Swap)是其中最核心的原语,它的原子性直接由 CPU 提供。
CPU 级别的原子操作支持
现代 CPU 在硬件层面提供了对单条内存访问指令的原子保障,但仅限于满足对齐、大小等条件的简单读写(如 4 字节对齐的 int)。而像“读-改-写”这类复合操作(例如 i++),天然不是原子的——中间可能被中断或并发修改。为此,CPU 提供了专门的原子指令:
- x86/x64:使用
lock cmpxchg指令实现 CAS;lock前缀会锁定总线或缓存行(取决于架构和操作数大小),阻止其他核心/线程在同一时间修改同一缓存行。 - ARM64:使用
ldxr(load-exclusive) +stxr(store-exclusive)配对。CPU 会标记某地址为“独占监视”,后续stxr成功当且仅当该地址未被其他核心修改过——失败则需重试。 - RISC-V:类似 ARM,用
lr.w/sc.w(load-reserved / store-conditional)机制。
std::atomic::compare_exchange_weak/strong 的底层行为
这两个函数最终映射到上述 CPU 指令。区别在于:
-
compare_exchange_weak允许“伪失败”(spurious failure):即使预期值匹配,也可能因底层机制(如 ARM 的独占监视被意外清除)返回 false。适合循环重试场景,性能略高。 -
compare_exchange_strong保证:只要预期值匹配,就一定成功(无伪失败)。但某些平台(如早期 ARM)需额外检查+重试模拟,开销稍大。
典型用法
是循环尝试:
while (!val.compare_exchange_weak(expected, desired)) {
// expected 已被更新为当前实际值
}
内存序(memory order)不是原子性,但影响可见性
原子性只解决“执行不中断”,不解决“结果何时对其他线程可见”。std::memory_order 控制编译器重排和 CPU 指令重排,以及缓存同步时机:
-
memory_order_relaxed:只保证该操作自身原子,不约束前后内存访问顺序,也不触发 cache coherency 同步(最快,适合计数器等无需同步语义的场景)。 -
memory_order_acquire(读)/memory_order_release(写):构成“获取-释放”同步,保证本线程中该操作前后的内存访问不会跨过它重排,并在多核间建立 happens-before 关系。 -
memory_order_seq_cst(默认):最强语义,所有线程看到的操作顺序一致,相当于全局顺序锁,性能开销最大。
编译器与运行时的协作
std::atomic 对象在编译期会被标记为不可分割访问(禁止拆解为多个 mov 指令),并根据模板参数类型选择对应宽度的原子指令(如 atomic → 32 位指令)。对于不支持原生原子操作的类型(如过大结构体),std::atomic 会退化为内部加锁(如 mutex),此时原子性由互斥量保证,而非硬件指令——但这已不属于“无锁原子操作”范畴。
# ai
# 这类
# 也不
# 多个
# 并在
# 已被
# 而非
# 这两个
# app
# 见性
# 循环
# 并发
# 对象
# c++
# int
# 字节
# 区别
# 线程
# 架构
# red
# 无锁
# 重试
# 结构体
# while
# 多核
# Conditional
相关栏目:
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
AI推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
SEO优化<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
技术百科<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
谷歌推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
百度推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
网络营销<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
案例网站<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
精选文章<?muma echo $count; ?>
】
相关推荐
- Python脚本参数接收_sys与argparse
- 如何使用Golang实现多重错误处理_Golang
- php打包exe后无法读取环境变量_变量配置方法【
- c++怎么使用类型萃取type_traits_c+
- 如何使用Golang实现路由分组管理_Golang
- Windows 10怎么隐藏特定更新补丁_Wind
- Linux如何安装Tomcat应用服务器_Linu
- PyTorch DDP 多进程训练在 Kaggle
- Mac如何与安卓手机传文件_Mac和Android
- win11 OneDrive怎么彻底关闭 Win1
- PHP 中如何在函数内持久化修改引用变量的指向
- Win11如何隐藏桌面图标 Win11一键隐藏/显
- Windows10如何更改日期格式_Win10区域
- Python抽象类与接口设计_规范说明【指导】
- 如何使用Golang sort排序切片_Golan
- Win11怎么关闭键盘按键音_Win11禁用打字声
- Windows10无法连接到Internet_Wi
- 小程序里php怎么变mp4_小程序调用php生成m
- Win11怎么开启智能存储_Windows11存储
- Win10电脑怎么设置休眠快捷键_Windows1
- Windows10如何删除Windows.old_
- PowerShell怎么创建复杂的XML结构
- Python对象比较排序规则_集合使用说明【指导】
- Win11怎么清理C盘系统错误报告_Win11清理
- Python装饰器设计思路_功能增强机制说明【指导
- c++怎么使用std::unique实现去重_c+
- Win10怎样卸载自带Edge_Win10卸载Ed
- php订单日志怎么记录评价_php记录订单评价日志
- Win11怎么设置默认邮件客户端 Win11修改M
- Win11 explorer.exe频繁崩溃_修复
- Win11怎么设置右键刷新选项_Windows11
- ACF 教程:如何正确更新嵌套在多层 Group
- Windows蓝屏错误0x00000023怎么修复
- Win11怎么关闭自动修复_跳过Win11开机自动
- Win11如何更改用户账户文件夹名称 Win11修
- Windows10系统怎么查看设备管理器_Win1
- Mac怎么进行语音输入_Mac听写功能设置与使用【
- Win11怎么设置开机问候语_自定义Win11锁屏
- php本地部署支持nodejs吗_php与node
- php做exe支持多线程吗_并发处理实现方式【详解
- Win10怎样清理C盘阿里旺旺缓存_Win10清理
- Windows 10怎么把任务栏放在屏幕上方_Wi
- 如何在Golang中处理URL参数_Golang
- Python实现图数据库操作_Neo4j核心CRU
- Win11如何关闭小娜Cortana Win11禁
- 如何在Golang中实现WebSocket广播_使
- 一文详解网站被黑客入侵挂马解决办法
- Win11怎么用设置清理回收站_Win11设置清理
- Win11相机打不开提示错误怎么修_相机权限开启与
- 如何使用正则表达式精确匹配最多含一个换行符的 st

QQ客服