C++: std::once_flag 和 std::call_once

std::once_flag 和 std::call_once

std::once_flag 和 std::call_once 是 C++11 引入的同步原语,用于确保某个函数在多线程环境中只被执行一次。它们位于 头文件中,主要用于实现线程安全的初始化操作。

std::once_flag

概述

类型:std::once_flag 是一个结构体,用于记录某个函数是否已经被调用过。
用途:与 std::call_once 配合使用,确保某个函数在多线程环境中只被执行一次。

std::once_flag my_flag;

std::call_once

函数:std::call_once 是一个函数模板,用于确保某个函数在多线程环境中只被执行一次。

参数:
std::once_flag& flag:一个 std::once_flag 对象,用于记录函数是否已经被调用过。

Function&& f:要执行的函数或可调用对象。

Args&&… args:传递给函数的参数。

std::once_flag my_flag;

void initialize() {
    // 初始化代码
}

void some_function() {
    std::call_once(my_flag, initialize);
}

示例代码

以下是一个完整的示例,展示了如何使用 std::once_flag 和 std::call_once 来确保某个函数在多线程环境中只被执行一次:

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

std::once_flag my_flag;

void initialize() {
    std::cout << "Initialization code executed" << std::endl;
}

void thread_function() {
    std::call_once(my_flag, initialize);
}

int main() {
    std::thread t1(thread_function);
    std::thread t2(thread_function);
    std::thread t3(thread_function);

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

    return 0;
}

底层实现

std::once_flag 和 std::call_once 的底层实现依赖于操作系统提供的同步机制,通常使用互斥锁(mutex)和条件变量(condition variable)来确保线程安全。

std::once_flag

std::once_flag 内部维护一个状态,用于记录函数是否已经被调用过。
这个状态通常是一个原子变量(atomic variable),确保在多线程环境下的操作是原子的。


std::call_once

std::call_once 内部使用一个互斥锁来保护对 std::once_flag 状态的访问。
如果函数尚未被调用,std::call_once 会锁定互斥锁,执行函数,然后更新 std::once_flag 的状态。
如果函数已经被调用,std::call_once 会立即返回,不会再次执行函数。
### 使用 `std::call_once` 创建单例模式 为了确保线程安全并仅初始化一次对象,可以利用 C++11 中引入的 `std::call_once` 函数配合 `std::once_flag` 来实现单例模式。这种方式能够有效防止多线程环境下多次实例化问题的发生。 下面是一个基于上述方法构建的 Singleton 类模板示例: ```cpp #include <iostream> #include <mutex> template<typename T> class Singleton { private: static T* instance; static std::once_flag initFlag; protected: // 构造函数设为保护类型以阻止外部直接创建对象 Singleton() {} public: ~Singleton() {} // 获取唯一实例的方法 static T& GetInstance() { std::call_once(initFlag, [](){ instance = new T(); }); return *instance; } // 删除拷贝构造函数赋值操作符来保证单一性 Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete; }; // 静态成员变量定义与初始化 template<typename T> T* Singleton<T>::instance = nullptr; template<typename T> std::once_flag Singleton<T>::initFlag; int main() { auto& obj = Singleton<MyClass>::GetInstance(); // 进一步的操作... } ``` 此代码片段展示了如何通过静态局部变量以及 lambda 表达式的组合方式,在首次调用 `GetInstance()` 方法时完成类实例的一次性初始化过程[^1]。 同时也删除了复制控制成员(即拷贝构造函数赋值运算符),从而确保该类不会被意外地重复实例化[^2]。 值得注意的是,这种方法依赖于 C++11 或更新的标准支持;因此对于某些旧版编译器可能无法正常工作[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

可能只会写BUG

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值