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

调用std::call_once前检查initialized布尔变量是否安全?能否降低同步开销?

关于std::call_once前检查initialized变量的安全性与开销问题

安全性:你的写法不安全

直接读写普通bool类型的initialized会导致数据竞争,属于C++标准定义的未定义行为:

  • 当一个线程在lambda中设置initialized = true,其他线程读取这个变量时,没有任何同步机制约束,可能出现“看到initialized为true,但data还没完成初始化”的情况——编译器或CPU可能对指令重排序,导致初始化data的操作和设置initialized的操作在其他线程眼里顺序颠倒,最终触发assert失败或者读取到垃圾数据。

同步开销:你的做法没有意义,反而添乱

你想通过提前检查跳过std::call_once来降低开销,但实际上:

  • std::call_once本身已经做了优化:第一次调用会同步等待初始化完成,后续所有调用都会快速返回(内部已经维护了初始化完成的标记,不需要每次加锁等待)。
  • 你额外加的不安全检查不仅没降低开销,还引入了未定义行为,完全是画蛇添足。

正确的处理方式

方案1:直接用std::call_once(推荐)

去掉多余的initialized变量,完全依赖std::call_once的机制,代码更简洁安全:

struct Data {
    std::vector<int> data;
    std::once_flag flag;
};

int run(Data& d, int l, int r) {
    std::call_once(d.flag, [&d]() {
        d.data.resize(5);
        std::generate(d.data.begin(), d.data.end(), [g = std::mt19937(std::random_device{}())]() mutable {
            return g() % 10;
        });
    });

    // read only ops:
    assert(d.data.size() == 5);
    return std::accumulate(d.data.cbegin() + l, d.data.cbegin() + r, 0);
}

方案2:用原子变量做快速检查(仅在极端场景下考虑)

如果确实需要提前跳过std::call_once,必须把initialized改成原子变量,保证读写的同步性:

struct Data {
    std::vector<int> data;
    std::once_flag flag;
    std::atomic<bool> initialized = false;
};

int run(Data& d, int l, int r) {
    if (!d.initialized.load(std::memory_order_acquire)) {
        std::call_once(d.flag, [&d]() {
            d.data.resize(5);
            std::generate(d.data.begin(), d.data.end(), [g = std::mt19937(std::random_device{}())]() mutable {
                return g() % 10;
            });
            d.initialized.store(true, std::memory_order_release);
        });
    }

    // read only ops:
    assert(d.data.size() == 5);
    return std::accumulate(d.data.cbegin() + l, d.data.cbegin() + r, 0);
}

但要注意:这种方式的收益非常有限,因为std::call_once的后续调用已经足够快,额外的原子操作开销可能抵消掉所谓的性能提升,只有当run函数被极其频繁调用且初始化完成后调用量极大时,才值得考虑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 02:22:44