atomic 是 C++ 中实现无锁并发的核心工具,通过 std::atomic 模板类保证对共享变量的操作原子性,避免数据竞争;它支持 int、bool、指针等类型,并提供 load、store、exchange、compare_exchange_weak/strong、fetch_add/sub 等原子操作,底层依赖 CPU 的 CAS 等原子指令;示例中多个线程并发调用 fetch_add 实现安全计数,无需互斥锁;内存序(memory order)控制同步行为与性能,包括 relaxed、acquire、release、acq_rel 和 seq_cst,需根据场景选择以平衡效率与一致性;atomic 可用于实现自旋锁、无锁队列等结构,但需注意 ABA 问题、类型是否 lock-free 及调试复杂性,合理使用可提升高性能场景下的并发效率。

在C++中,atomic 是实现无锁编程和并发安全的核心工具之一。它提供了一种线程安全的方式来访问和修改共享数据,而无需使用互斥锁(mutex),从而提升性能并避免死锁问题。
什么是 atomic?
std::atomic 是一个模板类,用于封装某种类型的变量(如 int、bool、指针等),保证对该变量的操作是原子的——即不会被多个线程同时干扰。常见类型有:
- std::atomic
- std::atomic
- std::atomic
- std::atomic_flag(最轻量的原子布尔标志)
这些操作在底层通常由CPU提供的原子指令(如CAS、LL/SC等)支持。
基本用法示例
以下是一个简单的计数器例子,展示如何用 atomic 实现线程安全的递增:
立即学习“C++免费学习笔记(深入)”;
#include <atomic>
#include <thread>
#include <vector>
#include <iostream>
std::atomic<int> counter{0};
void increment() {
for (int i = 0; i < 1000; ++i) {
counter.fetch_add(1, std::memory_order_relaxed);
}
}
int main() {
std::vector<std::thread> threads;
for (int i = 0; i < 10; ++i) {
threads.emplace_back(increment);
}
for (auto& t : threads) {
t.join();
}
std::cout << "Final counter value: " << counter.load() << '\n';
return 0;
}
这里使用了 fetch_add 方法,它原子地增加变量值。即使多个线程同时调用,也不会出现数据竞争。
常用原子操作方法
std::atomic 提供多种操作接口,适应不同场景:
- load():原子读取当前值
- store(val):原子写入新值
- exchange(val):设置新值并返回旧值
- compare_exchange_weak() 和 compare_exchange_strong():比较并交换(CAS),用于实现无锁结构的关键操作
- fetch_add(), fetch_sub():原子加减(适用于整型和指针)
CAS 操作典型用法:
std::atomic<int> val{0};
int expected = val.load();
while (!val.compare_exchange_weak(expected, expected + 1)) {
// 如果 val 被其他线程改了,expected 会被更新,循环重试
}
内存序(Memory Order)控制
atomic 支持指定内存顺序,影响性能与同步强度。常见的选项包括:
- std::memory_order_relaxed:仅保证原子性,不进行同步或顺序约束,最快
- std::memory_order_acquire:用于 load,确保之后的读写不会被重排到该操作前
- std::memory_order_release:用于 store,确保之前的读写不会被重排到该操作后
- std::memory_order_acq_rel:acquire + release,常用于读-改-写操作
- std::memory_order_seq_cst:默认最强一致性模型,所有线程看到相同操作顺序
例如,实现一个简单的自旋锁:
std::atomic<bool> lock_flag{false};
void spin_lock() {
while (lock_flag.exchange(true, std::memory_order_acquire)) {
// 等待解锁
}
}
void spin_unlock() {
lock_flag.store(false, std::memory_order_release);
}
无锁编程注意事项
虽然 atomic 强大,但无锁编程难度较高,需注意:
- 不是所有类型都支持原子操作,可通过 std::atomic<T>::is_always_lock_free 检查是否真正“无锁”
- 复杂数据结构(如链表、队列)需精心设计 CAS 循环逻辑,防止ABA问题(可用带版本号的指针解决)
- 过度依赖 seq_cst 可能降低性能,应根据实际同步需求选择合适内存序
- 调试困难,建议配合静态分析工具和TSAN(ThreadSanitizer)检测数据竞争
基本上就这些。合理使用 C++ atomic 能写出高效且线程安全的代码,尤其适合高性能服务器、实时系统等对延迟敏感的场景。关键是理解原子操作的本质和内存模型行为,才能写出正确又高效的无锁程序。











