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

为何使用C++ seq_cst内存模型时程序出现不符合预期的结果?

问题:seq_cst内存模型下为何两个断言条件同时成立?

背景与原示例

我从某文档的acquire/release章节取出示例并改写为bool版本:

-Thread 1-
y.store (true, memory_order_release);

-Thread 2-
x.store (true, memory_order_release);

-Thread 3-
assert (y.load (memory_order_acquire) == true && x.load (memory_order_acquire) == false)

-Thread 4-
assert (y.load (memory_order_acquire) == false && x.load (memory_order_acquire) == true)

该文档指出:

如果改用顺序一致(sequentially consistent)模型,那么两个存储操作中必然有一个先发生于(happen-before)另一个(具体顺序在运行时确定),线程间的值会同步,因此如果其中一个断言成立,另一个断言必然失败。

我按照这个逻辑,用std::memory_order_seq_cst实现了如下C++代码,但程序偶尔会输出"success!!! iteration number: ",也就是x_before_y和y_before_x同时为true,这和文档描述不符,请问原因是什么?

#include <atomic>
#include <thread>
#include <vector>
#include <iostream>

bool test() {
    std::atomic_bool is_started{false};

    std::atomic_bool x{false};
    std::atomic_bool y{false};

    std::atomic_bool x_before_y{false}; // 标记store(x, true)先于store(y, true)
    std::atomic_bool y_before_x{false}; // 标记store(y, true)先于store(x, true)

    std::thread t1([&]{ // -Thread 1-
        while (!is_started.load()) {}

        y.store(true, std::memory_order_seq_cst); // store(y, true)
    });

    std::thread t2([&]{ // -Thread 2-
        while (!is_started.load()) {}

        x.store(true, std::memory_order_seq_cst); // store(x, true)
    });

    std::thread t3([&] { // -Thread 3-
        while (!is_started.load()) {}

        if (!y.load(std::memory_order_seq_cst) && x.load(std::memory_order_seq_cst)) {
            x_before_y.store(true);
        }
    });

    std::thread t4([&]{ // -Thread 4-
        while (!is_started.load()) {}

        if (y.load(std::memory_order_seq_cst) && !x.load(std::memory_order_seq_cst)) {
            y_before_x.store(true);
        }
    });

    is_started.store(true);

    t1.join();
    t2.join();
    t3.join();
    t4.join();

    return x_before_y.exchange(false) && y_before_x.exchange(false);
}

int main() {
    for (int i = 0; i < 100000000; i++) {
        if (test()){ 
            std::cout << "success!!! iteration number: " << i << std::endl;
            return 1;
        }
        if (i % 1000000 == 0) {
            std::cout << "still running" << std::endl;
        }
    }
    
    std::cout << "fail :(" << std::endl;
    return 0;
}

原因分析

1. 代码逻辑与原文档断言的核心意图不符

原文档的断言是验证同一全局状态下的两个值组合:要么y为true且x为false,要么y为false且x为true。但你的代码中,t3和t4是独立异步执行的,它们的两次读取(x和y)并非针对同一个全局状态:

  • t3可能先读取y为false、x为true,设置x_before_y;之后t4在t1完成y的存储后,读取y为true,同时t2的x存储还没被t4观测到,读取x为false,设置y_before_x。
  • 这两个线程的观察发生在不同时间点,组合起来就会出现两个标记同时为true的情况,完全偏离了原示例“同一状态下两个断言互斥”的核心逻辑。

2. seq_cst的全局总序不代表所有线程同时看到同一状态

顺序一致模型保证所有seq_cst操作存在一个全局的执行顺序,但每个线程读取seq_cst变量时,是在自身执行流中看到这个总序的某个阶段:

  • 假设全局总序是t2的x.store先于t1的y.store,但t4可能在t2的x.store完成前就读取x(得到false),之后读取y时t1的y.store已完成(得到true);而t3可能在t2的x.store完成后读取x(得到true),在t1的y.store完成前读取y(得到false)。
  • 这种情况下,两个线程分别观察到了全局总序的不同切片,自然会同时触发两个标记。

3. 错误映射了“happen-before”的判断逻辑

你用x_before_y和y_before_x标记的是“某个线程观察到的状态”,而非两个存储操作实际的happen-before关系。即使两个存储操作存在明确的全局顺序,线程的异步观察也可能捕捉到中间状态,导致错误的标记。

修正方向

要准确模拟原文档的逻辑,需确保每个线程对x和y的读取是一个连贯的状态快照,并且验证的是“同一状态下两个断言互斥”。例如,可以让单个线程依次检查两种断言条件,或者让t3和t4在读取x和y后,仅当组合状态符合断言时才标记,同时避免异步观察的交叉干扰。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 20:54:56