为何用std::atomic实现单次执行会出现多次执行问题?
问题:std::atomic实现的单次执行逻辑为何在多线程下失效?
我用以下代码实现某段逻辑仅执行一次:
class Test { public: void foo() { if (m_barrier.exchange(true)) { return; } // This should only execute once } private: std::atomic<bool> m_barrier { false }; };
多线程会多次调用foo()函数,预期exchange下方的代码每个对象实例仅执行一次。我原本认为这段代码是正确的,但发现有时该代码会执行多次。
运行环境为Android的aarch64架构CPU,已在三款不同手机上复现问题。不确定是Android标准库的bug,还是我的代码本身无法保证单次执行?
补充说明:
- 请勿建议使用
std::once,因某些原因无法采用。 - 我知道可以用
std::mutex搭配非atomic bool替代,我的问题是为何std::atomic实现不具备线程安全性?
分析与解答
你的代码逻辑本身从C++标准层面是正确的:std::atomic::exchange是原子操作,会原子性地将值替换为true并返回旧值。理论上,只有第一个调用foo()的线程会得到旧值false,进入后续逻辑;其他线程得到旧值true,直接返回。
但在Android aarch64平台出现多次执行的情况,大概率是Android标准库的atomic实现存在问题,或者是平台特定的内存模型行为未被正确处理:
- 内存顺序问题:默认情况下
exchange使用的是std::memory_order_seq_cst,这是最严格的内存顺序,保证所有线程看到的操作顺序一致。但如果Android的libc++实现对aarch64的atomic操作做了不符合标准的优化,比如偷偷降低了内存顺序,可能导致线程间的操作可见性出现问题。 - 硬件指令生成问题:aarch64的原子交换依赖
ldxr/stxr这样的独占加载/存储指令序列,若标准库的实现没有正确生成这些指令,或者存在指令重排序漏洞,可能导致多个线程同时进入临界区。 - 对象实例重复创建:如果存在多个
Test对象实例,每个实例的m_barrier是独立的,自然会各自执行一次逻辑——这不属于atomic的问题,需要排查对象创建逻辑。
总结:你的代码逻辑符合C++线程安全规范,问题大概率出在Android aarch64平台的标准库atomic实现上,而非代码本身的设计错误。
内容的提问来源于stack exchange,提问作者Kostya Vasilyev
相关产品推荐
相关产品推荐

