正确实现自旋锁需区分原子操作语义:一、用exchange(true)自旋检测旧值是否为false;二、用atomic_flag::test_and_set更高效;三、exchange(nullptr)适用于资源接管;四、exchange(0)用于同步归零。

如果您尝试使用 std::atomic::exchange 实现自旋锁,但发现多个线程能同时进入临界区或行为不符合排他性预期,则可能是混淆了无条件交换与条件获取的本质区别。以下是基于该操作实现自旋锁核心逻辑的多种可行路径:
一、基于 std::atomic::exchange 的自旋锁结构
该方法利用 exchange(true, memory_order_acquire) 的原子写入特性,在每次尝试加锁时强制将标志设为 true,并返回旧值;若旧值为 false,说明此前未被占用,当前线程成功“抢占”锁。其本质是将锁状态翻转动作与占有判定合并为单次原子操作。
1、声明一个全局或成员变量:std::atomic
2、在 lock() 函数中执行循环:当 lock_flag.exchange(true, std::memory_order_acquire) 返回 true 时,继续自旋;返回 false 时跳出循环。
3、在 unlock() 函数中调用:lock_flag.store(false, std::memory_order_release);
二、基于 std::atomic_flag::test_and_set 的标准 lock-free 自旋锁
std::atomic_flag 是 C++ 标准唯一强制要求 lock-free 的原子类型,其 test_and_set() 操作在硬件层面对应单条原子指令(如 x86 的 XCHG),天然满足自旋锁对低延迟和无 ABA 风险的要求,且避免了 std::atomic
1、正确初始化标志:std::atomic_flag flag = ATOMIC_FLAG_INIT;(C++11/14)或 std::atomic_flag flag{};(C++17+)
2、在 lock() 中循环调用:while (flag.test_and_set(std::memory_order_acquire)) { /* PAUSE 或 yield */ }
3、在 unlock() 中调用:flag.clear(std::memory_order_release);
三、基于 std::atomic::exchange 的指针级资源接管式锁
当需在加锁时独占接管某个动态资源(如链表头节点、缓冲区句柄),可使用 std::atomic
1、定义原子指针:std::atomic
2、在临界入口处执行:Node* old_head = head.exchange(nullptr, std::memory_order_acq_rel);
3、检查 old_head 是否非空,若非空则本线程获得该资源独占权,后续可安全遍历、释放或重构。
四、基于 std::atomic::exchange 的计数器归零型同步点
在某些协作式终止协议中,需确保所有线程看到统一的“重置信号”,此时可使用 counter.exchange(0) 替代先 load 再 store 的两步操作,防止中间被其他线程修改。该方式虽不构成传统意义上的锁,但在多线程协同归零、批量刷新等场景下构成关键同步原语。
1、声明带初始值的原子整数:std::atomic
2、在同步点执行:int previous = counter.exchange(0, std::memory_order_seq_cst);
3、根据 previous 值判断是否为首次触发归零操作,并执行对应分支逻辑。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











