std::atomic 是 C++11 提供的无锁原子操作工具,支持 load/store/exchange/compare_exchange 等操作,需合理选用 memory_order 并注意 lock-free 性、ABA 问题及正确性验证。

std::atomic 是 C++11 引入的核心工具,用于在多线程环境中安全地读写共享变量,无需互斥锁(mutex),从而实现无锁(lock-free)编程。它的关键在于:所有操作都是原子的,不会被线程调度打断,且编译器和 CPU 会按需插入内存屏障,防止重排序导致的数据竞争。
基础用法:声明与基本操作
std::atomic
-
load():原子读,等价于
operator T(),默认 memory_order_seq_cst(最强顺序) -
store(val):原子写,等价于
operator=(val) - exchange(val):原子地将原值替换为 val,并返回旧值
- compare_exchange_weak(expected, desired):若当前值等于 expected,则设为 desired 并返回 true;否则将当前值写入 expected 并返回 false(可能伪失败,需循环重试)
实现无锁计数器(典型例子)
下面是一个线程安全的无锁自增计数器,不依赖 mutex:
std::atomiccounter{0}; void increment() { counter.fetch_add(1, std::memory_order_relaxed); }
int get_value() { return counter.load(std::memory_order_acquire); }
这里用 fetch_add 替代 read-modify-write 手动实现,避免竞态。注意:memory_order_relaxed 适用于仅需原子性、不依赖其他内存操作顺序的场景(如计数器);若需同步其他数据,应升级为 acquire/release 或保持默认 seq_cst。
立即学习“C++免费学习笔记(深入)”;
实现无锁栈(push/pop)
无锁栈依赖 compare_exchange_weak 实现 ABA 问题规避(通常配合 tag pointer 或 hazard pointer,简单版可先忽略 ABA):
struct Node {
int data;
Node* next;
};
std::atomic head{nullptr};
void push(int data) {
Node* node = new Node{data, nullptr};
node->next = head.load(std::memory_order_relaxed);
while (!head.compare_exchange_weak(node->next, node,
std::memory_order_release, std::memory_order_relaxed)) {
// 若 head 已变,node->next 被自动更新为当前 head,继续重试
}
}
pop 类似,但需小心处理内存释放(建议搭配 std::shared_ptr 或专用内存回收机制,否则易出现 use-after-free)。
注意事项与常见陷阱
无锁 ≠ 无脑高效。实际使用中要注意:
- 不是所有 std::atomic
都是 lock-free:可用 is_lock_free()检查,例如某些平台下 atomic可能回退到内部锁 - 过度依赖 seq_cst 会显著降低性能;应根据同步需求选择合适 memory_order(如 producer-consumer 场景常用 release/acquire)
- compare_exchange_weak 可能因硬件原因“假失败”,必须放在 do-while 或 while 循环中重试;strong 版本不假失败但可能更慢
- 无锁结构的正确性极难验证,建议优先使用成熟库(如 folly::AtomicSharedPtr、boost::lockfree)或标准容器(std::queue 不是无锁的,勿误用)










