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

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 会立即返回,不会再次执行函数。
<think>我们正在讨论C++中的std::once_flagstd::call_once。这两个工具用于确保某个函数只被调用一次,即使在多线程环境下也是如此。这通常用于实现线程安全的单例模式,或者初始化只应执行一次的资源。 我们将首先解释这两个组件的用途基本用法,然后给出一个示例代码,最后根据内容提出相关问题。 </think>### `std::once_flag` 与 `std::call_once` 的用法 `std::once_flag` `std::call_once` 是 C++11 引入的线程安全初始化工具,用于确保某个操作在多线程环境中仅执行一次,比双重检查锁定更简洁安全。以下是核心要点用法: #### **核心作用** 1. **`std::once_flag`**: - 状态标志,记录关联操作是否已执行(不可复制,不可移动)。 2. **`std::call_once`**: - 接受一个 `once_flag` 可调用对象(如函数、lambda)。 - **保证**:无论多少线程调用,可调用对象仅执行一次。 --- #### **使用步骤** 1. 声明全局/静态的 `once_flag` 对象(通常与单例关联)。 2. 在需要初始化的位置调用 `std::call_once`,传入操作逻辑。 #### **示例:线程安全的单例模式** ```cpp #include <mutex> class Singleton { public: static Singleton& getInstance() { std::call_once(initFlag, []() { instance.reset(new Singleton); }); return *instance; } private: Singleton() {} // 私有构造函数 static std::unique_ptr<Singleton> instance; static std::once_flag initFlag; // 初始化标志 }; // 静态成员初始化 std::unique_ptr<Singleton> Singleton::instance; std::once_flag Singleton::initFlag; ``` #### **关键特性** - **隐式同步**:内部通过锁原子操作保证线程安全,无需手动管理内存顺序。 - **异常安全**:若操作抛出异常,其他线程会重新尝试执行。 - **替代场景**: - 替代双重检查锁定,避免指令重排风险。 - 初始化全局配置、日志系统等需一次性执行的资源。 --- #### **与双重检查锁定的对比** | 特性 | `std::call_once` | 双重检查锁定 | |---------------------|--------------------------------|--------------------------| | **复杂度** | 更简洁(无需显式锁/原子操作) | 需手动处理内存顺序锁 | | **安全性** | 无指令重排风险 | 需谨慎使用 `volatile`/原子 | | **适用性** | C++11 及以上 | 跨语言通用 |
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

可能只会写BUG

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

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

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

打赏作者

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

抵扣说明:

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

余额充值