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

如何在多线程环境下使call_once()在构造函数中正确工作?

在构造函数中使用std::call_once的正确姿势

我之前专门在多线程环境下测试过std::call_once()对普通变量的控制,实际行为完全符合预期——确实能保证目标函数只被执行一次。但在构造函数里想用它实现延迟初始化的时候,踩了不少坑,折腾了挺久才摸清楚正确的用法。

下面是我基于Stroustrup《C++程序设计语言》第4版的示例修改后的代码,文件名是initialize_once_class_ctor.cpp,专门用来演示如何在构造函数场景下正确使用std::once_flag和std::call_once()完成延迟初始化:

#include <iostream>
#include <mutex>
#include <thread>
#include <chrono>

class DelayedInitClass {
private:
    // 必须是静态成员,确保所有实例共享同一个初始化标记
    static std::once_flag init_flag;
    // 需要延迟初始化的共享资源
    static int shared_data;

    // 实际执行初始化的私有函数
    void do_init() {
        // 模拟耗时的初始化操作,比如加载配置、创建全局资源等
        std::this_thread::sleep_for(std::chrono::milliseconds(200));
        shared_data = 1024;
        std::cout << "Shared resource initialized by thread ID: " << std::this_thread::get_id() << std::endl;
    }

public:
    DelayedInitClass() {
        // 在构造函数中调用call_once,确保初始化只执行一次
        // 注意:如果是成员函数作为回调,需要传入this指针作为额外参数
        std::call_once(init_flag, &DelayedInitClass::do_init, this);
    }

    // 提供外部访问共享资源的接口
    void use_shared_data() {
        std::cout << "Thread " << std::this_thread::get_id() << " accessed shared data: " << shared_data << std::endl;
    }
};

// 静态成员变量的类外初始化
std::once_flag DelayedInitClass::init_flag;
int DelayedInitClass::shared_data = 0;

int main() {
    const int thread_num = 6;
    std::thread threads[thread_num];

    // 创建多个线程,每个线程都构造类实例
    for (int i = 0; i < thread_num; ++i) {
        threads[i] = std::thread([](){
            DelayedInitClass instance;
            instance.use_shared_data();
        });
    }

    // 等待所有线程完成
    for (auto& t : threads) {
        t.join();
    }

    return 0;
}

关键注意事项:

  • std::once_flag必须声明为静态成员变量:如果是普通成员,每个类实例都会有自己的flag,根本起不到全局控制初始化次数的作用,这是最容易踩的坑
  • 如果初始化函数是类的非静态成员函数,调用std::call_once时必须传递this指针作为额外参数,否则无法正确调用成员函数
  • 即使多个线程同时进入构造函数,std::call_once也会保证初始化函数仅被执行一次,完全避免了多线程下的竞态问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 10:58:17