atomic初始化必须显式用{}或先构造再store,禁用=赋值;load/store是安全读写方式,避免隐式转换;compare_exchange_weak需配合循环使用;atomic_flag专用于无锁同步,与atomic定位不同。

atomic 的初始化必须显式或用{},不能用=赋值
直接写 std::atomic<int> a = 42;</int> 在 C++17 及以后会编译失败,因为 std::atomic 删除了拷贝构造和拷贝赋值。它不是普通类型,不支持隐式转换初始化。
正确写法只有两种:
-
std::atomic<int> a{42};</int>(推荐,统一初始化) -
std::atomic<int> a; a.store(42);</int>(先默认构造再存)
用 = 看似像赋值,实则是调用拷贝构造——而这个操作被禁用了。很多新手卡在这一步,报错信息类似 use of deleted function 'std::atomic<int>::atomic(const std::atomic<int>&)'</int></int>,本质是误当成了可拷贝类型。
load() 和 store() 是最安全的读写方式
直接访问 a(比如 int x = a;)在旧标准中可能不合法,C++20 虽允许隐式转换,但语义不明确:它等价于 a.load() 还是 a.load(std::memory_order_seq_cst)?依赖编译器实现容易出问题。
明确写出来更可控:
-
a.load()默认是std::memory_order_seq_cst,适合绝大多数场景 -
a.store(100)同样默认强序,避免重排导致的逻辑错乱 - 若需性能优化,可显式指定内存序,如
a.load(std::memory_order_acquire),但必须理解同步语义,否则极易引入竞态
别图省事写 if (a) { ... } —— 这会触发隐式 load(),但无法控制内存序,也掩盖了意图。
compare_exchange_weak 和 compare_exchange_strong 的区别很实际
这是实现无锁栈、计数器、状态机的核心函数。两者都做“比较并交换”,但行为不同:
-
compare_exchange_weak允许“伪失败”(spurious failure):即使当前值匹配,也可能返回false,常因底层 CAS 指令被中断(如 x86 上的lock cmpxchg在某些情况下会失败) -
compare_exchange_strong保证:值匹配就一定成功,不匹配就一定失败;但某些平台(如 ARM)开销略大
实际写法通常是循环 + weak:
int expected = a.load();
do {
int desired = expected * 2;
} while (!a.compare_exchange_weak(expected, desired));
用 weak 配合循环是标准做法,既规避伪失败影响,又保持高性能。用 strong 单次调用只适合确定不会失败的简单判断场景。
atomic 和 atomic_flag 是两回事
std::atomic<bool></bool> 是通用原子类型,支持 load/store/exchange,还能当普通布尔用(if (done.load()))。但它不保证无锁(is_lock_free() 可能返回 false)。
std::atomic_flag 是唯一保证无锁的原子类型,仅提供 test_and_set() 和 clear(),初始状态总是 false,且必须用 ATOMIC_FLAG_INIT(C++20 起已弃用,改用默认构造)。
- 需要轻量级自旋锁?用
atomic_flag - 只是想在线程间传个开关信号?用
atomic<bool></bool>更自然 - 别试图对
atomic_flag做load()—— 它没这个接口
很多人以为 atomic_flag 是 atomic<bool></bool> 的“更快版本”,其实它们定位不同:一个是基础设施(锁原语),一个是数据同步载体。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











