You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用宽松原子操作的比较并交换(Compare-and-Swap)问题

原子操作内存顺序问题分析

示例代码

void foo(atomic<int> &x) {
    int i = 0;
    bool success = x.compare_exchange_strong(i, i + 2, memory_order_relaxed, memory_order_relaxed);
    assert(!success);
}

void bar(atomic<int> &x) {
    x.store(1, memory_order_relaxed);
}

int main() {
    atomic<int> x = 0;
    auto bar_thread = thread(bar, std::ref(x));
    sleep(1);
    auto foo_thread = thread(foo, std::ref(x));
    sleep(1);
    foo_thread.join();
    bar_thread.join();
}

问题描述

尽管代码中使用了sleep,但线程仍可能交错执行,不过可假设本示例中bar线程在foo线程执行前已完成。请问此场景下能否保证assert永远不触发?

我的理解是:x.store(1, memory_order_relaxed)虽是原子操作,但写入内容可能无法立即被其他线程感知,除非搭配acquire-release或顺序一致性内存顺序。我为compare_exchange_strong的失败参数传入memory_order_relaxed,理论上它可能读取x的初始值0,但实际assert从未触发(我知道这不代表必然结果)。

想请教:无论传入何种内存顺序,compare_exchange_strong最终都会与最后一次写入同步吗?我猜测x的初始值以memory_order_relaxed读取,仅当值与expected相等时,才执行更耗时的比较交换操作?

解答

结论

在假设bar线程完全在foo线程执行前完成的前提下,能保证assert永远不会触发。

关键解释

  • 原子操作的最终可见性:哪怕是memory_order_relaxed内存顺序,原子操作的核心特性是全局可见性的最终一致性。只要一个线程的原子写入操作完全完成,其他线程后续对该原子变量的任何原子读取(包括compare_exchange_strong中的读取动作)最终一定会看到这个写入值,不会永久停留在旧值。你提到的"无法立即感知"只是指relaxed不保证跨线程操作的顺序性,但不代表写入会永远不可见。
  • compare_exchange_strong的原子性逻辑:该操作是原子性地完成"读取当前值→与expected比较→条件写入"的整个流程,不存在先读取旧值再用旧值执行后续比较的情况。在本场景中,foo线程启动时bar的写入已经完成,compare_exchange_strong读取到的x值必然是1,和expected的0不相等,因此返回false,assert不会触发。
  • 内存顺序参数的作用:内存顺序影响的是跨线程操作之间的同步关系(比如是否让其他内存操作的可见性随之同步),但不会改变原子操作本身对目标变量的读写原子性,也不会阻止已完成的原子写入被后续原子读取看到。无论使用哪种内存顺序,只要bar的写入完全先于foo的操作,foo就能读到bar写入的1。

内容的提问来源于stack exchange,提问作者petabyte

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 14:24:57