c++中如何使用std::atomic_flag_c++最简单的自旋锁实现【详解】
发布时间 - 2026-01-27 00:00:00 点击率:次std::atomic_flag 是最轻量的无锁原子布尔类型,专为实现自旋锁设计,仅支持 test_and_set() 和 clear(),强制 lock-free 且初始化必须用 ATOMIC_FLAG_INIT 或 {}。
std::atomic_flag 是 C++ 中最轻量的原子布尔类型,它不提供 load() 或 store(),只支持 test_and_set() 和 clear() —— 这恰恰让它成为实现**无锁自旋锁**的理想起点。
为什么不用 std::atomic 做自旋锁?
看似更直观,但 std::atomic 的 exchange(true, std::memory_order_acquire) 在某些平台(如 ARM)可能生成较重的指令;而 std::atomic_flag 被标准强制要求是“无锁的”(lock-free),且 test_and_set() 默认使用 std::memory_order_seq_cst,语义更贴近互斥锁的 acquire/release 行为。
-
std::atomic_flag初始化必须用ATOMIC_FLAG_INIT(C++17 起可直接用{}值初始化) - 它不支持拷贝、赋值,天然防误用
- 没有
operator bool(),必须显式调用test_and_set()或clear()
最简自旋锁:spin_lock 类封装
核心逻辑就两行:循环调用 test_and_set() 直到返回 false(说明之前是未设置状态,抢锁成功);退出临界区时调用 clear()。
struct spin_lock {
std::atomic_flag flag = ATOMIC_FLAG_INIT;
void lock() {
while (flag.test_and_set(std::memory_order_acquire)) {
// 可选:__builtin_ia32_pause() 或 std::this_thread::yield()
}
}
void unlock() {
flag.clear(std::memory_order_release);
}
};
- 用
std::memory_order_acquire保证 lock 后的读写不被重排到锁获取前 - 用
std::memory_order_release保证 unlock 前的读写不被重排到锁释放后 - 若长期争用,空转消耗 CPU,建议在循环体内加
std::this_thread::yield()或 x86 的
_mm_pause()
常见误用与陷阱
看似简单,但几个细节一错就导致死锁或数据竞争:
立即学习“C++免费学习笔记(深入)”;
- 忘记初始化:写成
std::atomic_flag flag;是未定义行为 —— 必须用= ATOMIC_FLAG_INIT或{}(C++17) - unlock 时用了错误的 memory order:
flag.clear(std::memory_order_relaxed)会破坏同步语义,其他线程可能看不到临界区内的修改 - 构造函数里没初始化 flag,或多次调用
clear()而未配对lock(),会导致锁状态混乱 - 把
spin_lock放在栈上并跨线程传递(比如 move 到 lambda)—— 它不可移动、不可拷贝,运行时报错或静默 UB
和 std::mutex 对比:什么时候该用它?
自旋锁只适合「临界区极短 + 争用极少」的场景,比如保护一个计数器更新、或无锁结构中的某个标志位。
- 优势:无系统调用开销,上下文切换少,在低延迟关键路径中更快
- 劣势:持有锁时持续占用 CPU,高争用下吞吐反而更差;无法被操作系统调度器挂起,不能用于可能阻塞的操作(如 IO、sleep)
- 不要试图用它替代
std::mutex写业务逻辑 —— 几乎总是错的
真正需要它的场合,往往已经处于无锁编程的深水区,此时你大概率已在手写 std::atomic 状态机,而不是靠 std::atomic_flag 打天下。
# 操作系统
# 栈
# c++
# 无锁
# 为什么
# 天下
# 有锁
# 封装
# 构造函数
# bool
# int
# 循环
# Lambda
# 布尔类型
# operator
# 线程
# 布尔
# 死锁
# 不被
# 它不
# 用它
# 最轻
# 几个
# 放在
# 什么时候
# 已在
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
Laravel Seeder填充数据教程_Laravel模型工厂Factory使用
香港服务器网站推广:SEO优化与外贸独立站搭建策略
Laravel如何与Vue.js集成_Laravel + Vue前后端分离项目搭建指南
如何在阿里云虚拟机上搭建网站?步骤解析与避坑指南
Laravel中Service Container是做什么的_Laravel服务容器与依赖注入核心概念解析
php后缀怎么变mp4格式错误_修改扩展名提示格式不对怎么办【技巧】
JavaScript实现Fly Bird小游戏
如何在云服务器上快速搭建个人网站?
如何在云虚拟主机上快速搭建个人网站?
如何安全更换建站之星模板并保留数据?
Python正则表达式进阶教程_复杂匹配与分组替换解析
公司门户网站制作公司有哪些,怎样使用wordpress制作一个企业网站?
Linux安全能力提升路径_长期防护思维说明【指导】
如何快速查询网址的建站时间与历史轨迹?
如何在HTML表单中获取用户输入并结合JavaScript动态控制复利计算循环
EditPlus中的正则表达式实战(5)
实现点击下箭头变上箭头来回切换的两种方法【推荐】
Python结构化数据采集_字段抽取解析【教程】
郑州企业网站制作公司,郑州招聘网站有哪些?
Laravel如何实现本地化和多语言支持?(i18n教程)
网站建设保证美观性,需要考虑的几点问题!
Laravel如何使用Seeder填充数据_Laravel模型工厂Factory批量生成测试数据【方法】
湖南网站制作公司,湖南上善若水科技有限公司做什么的?
Laravel控制器是什么_Laravel MVC架构中Controller的作用与实践
php静态变量怎么调试_php静态变量作用域调试技巧【解答】
html5的keygen标签为什么废弃_替代方案说明【解答】
Laravel怎么写单元测试_PHPUnit在Laravel项目中的基础测试入门
如何确保FTP站点访问权限与数据传输安全?
作用域操作符会触发自动加载吗_php类自动加载机制与::调用【教程】
Laravel怎么实现微信登录_Laravel Socialite第三方登录集成
教你用AI将一段旋律扩展成一首完整的曲子
Laravel如何实现密码重置功能_Laravel密码找回与重置流程
Win11任务栏卡死怎么办 Windows11任务栏无反应解决方法【教程】
Laravel Fortify是什么,和Jetstream有什么关系
Win11怎么关闭专注助手 Win11关闭免打扰模式设置【操作】
如何用搬瓦工VPS快速搭建个人网站?
高防服务器:AI智能防御DDoS攻击与数据安全保障
如何在浏览器中启用Flash_2025年继续使用Flash Player的方法【过时】
黑客入侵网站服务器的常见手法有哪些?
Laravel怎么实现验证码(Captcha)功能
Win11怎么更改系统语言为中文_Windows11安装语言包并设为显示语言
QQ浏览器网页版登录入口 个人中心在线进入
阿里云网站搭建费用解析:服务器价格与建站成本优化指南
php 三元运算符实例详细介绍
Laravel事件和监听器如何实现_Laravel Events & Listeners解耦应用的实战教程
javascript中数组(Array)对象和字符串(String)对象的常用方法总结
如何在新浪SAE免费搭建个人博客?
北京网站制作的公司有哪些,北京白云观官方网站?
Android GridView 滑动条设置一直显示状态(推荐)
浅谈redis在项目中的应用


