不是必须,但C++17起推荐用std::atomic_flag flag{}值初始化;ATOMIC_FLAG_INIT已弃用,漏初始化会导致未定义行为;test_and_set()返回false表示获取锁成功,需配对使用memory_order_acquire和release;它不支持load或operator==,仅提供test_and_set()和clear()。
不是必须,但不推荐手动初始化。C++17 起 ATOMIC_FLAG_INIT 已弃用,正确做法是用值初始化:std::atomic_flag flag{};。如果写成 std::atomic_flag flag = ATOMIC_FLAG_INIT;,在 C++17+ 编译会报错或警告;若漏掉初始化(比如只声明 std::atomic_flag flag;),其内部状态未定义,test_and_set() 行为不可预测。
常见错误现象:程序偶发死锁或 flag.test_and_set() 返回 false 却没真正设为 true——基本就是未正确初始化。
std::atomic_flag flag{};(零初始化)flag.clear(std::memory_order_relaxed);
test_and_set() 是原子地“读取当前值并设为 true”,返回旧值。返回 false 表示此前未被占用,当前线程成功获取锁;返回 true 表示已被占用,需等待。
典型实现就是循环调用直到成功:
立即学习“C++免费学习笔记(深入)”;
while (flag.test_and_set(std::memory_order_acquire)) { // 可选:短暂让出 CPU,避免过度自旋 std::this_thread::yield();}
注意内存序:std::memory_order_acquire 保证后续读写不会被重排到锁获取之前;释放锁时必须配对使用 std::memory_order_release。
test_and_set(std::memory_order_acquire)
flag.clear(std::memory_order_release)
relaxed —— 它无法防止指令重排,导致临界区逻辑错乱yield() 不是必须,但在单核或高竞争场景下能降低 CPU 占用std::atomic_flag 没有 operator==,也不支持直接读取布尔值。它只提供 test_and_set() 和 clear() 两个原子操作。试图写 if (!flag) 或 flag.load() 会编译失败。
这是设计使然:避免“检查再设置”这种非原子的竞态操作。如果你需要“只读检查”,必须用 test_and_set() 并接受它会改变状态 —— 所以真正的“尝试获取”只能靠循环 + 原子操作完成。
load()、没有 operator bool、没有 is_lock_free() 的公开访问(虽然内部是 lock-free)test_and_set() 尝试,失败即空闲(返回 false),成功即已占(返回 true)test_and_set(),不循环它是最轻量的原子锁原语,但功能极简:无所有权、不支持递归、不阻塞线程、不通知等待者。适用于短临界区、低竞争、对延迟敏感的场景(如无锁数据结构内部同步),不适合通用互斥需求。
容易踩的坑包括:忘记释放锁导致死锁;在异常路径中未调用 clear();用在需要条件变量配合的场景却硬套 busy-wait。
clear(),建议用 RAII 封装(如自定义 scoped_lock 类)std::mutex 或更高级同步原语真正用好它,关键不是“怎么写”,而是想清楚:这个临界区是否足够短、是否确定不会抛异常、是否真的不能接受系统调用开销。