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

如何构造因编译器优化导致的C++并发Bug最小示例?

如何构造单核环境下编译器优化导致的并发Bug示例

问题背景

在演讲《Real-time Confessions in C++》的6分44秒处,展示了一类并发Bug的核心逻辑:

  • 线程A写入未同步的整数x
  • 一段时间后,线程B循环读取x
  • 线程B无法看到x的更新值,因为编译器优化认为线程B不会修改x,因此在线程启动时仅加载一次x的值。

演讲者旨在证明即使在单核机器上也需同步机制,否则编译器优化会导致代码出错。

我尝试构造该Bug的最小示例,编写了如下代码:

#include <string>
#include <iostream>
#include <thread>
#include <unistd.h>

int var;  // unsynchronized, i.e., no std::atomic or anything

void f() {
    for (int i = 0; i < 10; i++) {
        sleep(1);
        int x = var * var;
        std::cout << x << std::endl;
    }
}

int main() {
    var = 1;

    std::thread t(f);
  
    sleep(2);
    var = 10;

    t.join();
}

预期线程f()中编译器会将var的加载优化为仅在线程启动时执行,从而始终输出1,但实际输出为1后持续输出100。请问我哪里出错了?如何正确构造该并发Bug的最小示例?


问题原因与修复方案

为啥你的代码没复现预期的Bug?

你的代码里有两个细节直接掐断了编译器的优化空间:

  1. std::cout是带同步的操作:std::cout的输出会触发内存屏障,强制线程刷新内存状态,所以线程B每次输出后都会重新读一遍var的最新值,自然能看到主线程改的10。
  2. sleep(1)的存在:编译器没法确定sleep内部会不会偷偷修改var(比如通过全局状态),不敢冒险把var的读取提前到循环外面。

正确的最小示例怎么写?

要复现这个Bug,得把所有能触发内存同步的操作都删掉,同时让编译器确信:当前线程不会修改var,也没有其他可见的操作会影响var。

修改后的代码(必须开-O2/-O3优化编译):

#include <thread>
#include <unistd.h>

int var;
volatile int keep_running = 1; // 用volatile确保循环条件不会被优化掉

void worker() {
    int x;
    while (keep_running) {
        x = var * var; // 编译器会把var的读取提到循环外
        (void)x; // 告诉编译器x被用到了,别把计算优化没了
    }
}

int main() {
    var = 1;
    std::thread t(worker);
  
    sleep(2);
    var = 10; // 修改var,但线程worker看不到
    sleep(5); // 等几秒看效果
    keep_running = 0; // 让线程退出
    t.join();
}

验证方式

用GCC编译时加最高级优化参数:

g++ -std=c++11 -O3 bug.cpp -o bug -pthread

运行后,线程worker会全程使用var=1的值计算,完全看不到主线程设置的var=10——因为编译器会把代码优化成这样:

void worker() {
    int cached_var = var; // 只读取一次var
    int x = cached_var * cached_var;
    while (keep_running) {
        (void)x; // 循环里啥也不干,反复用缓存的x
    }
}

关键注意点

  • 必须用volatile修饰keep_running,不然编译器会把while(keep_running)优化成死循环,因为它觉得这个变量不会被外部修改。
  • 循环里不能加任何I/O、sleep或者系统调用,这些操作都会让编译器放弃激进优化。
  • 这个问题的本质是C++内存模型中未同步的数据竞争导致的未定义行为——编译器对于没有同步的变量,有权做任何它认为合理的优化,包括缓存值。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 15:07:13