std__call_once 的使用

std__call_once 的使用


std::call_once 是 C++11 中引入的一个标准库函数,属于 <mutex> 头文件。它用于确保某个特定的函数(或代码块)在多线程程序中 只执行一次。这是一个线程安全的操作,通常用于实现 单例模式 或 延迟初始化 等场景。

1. 功能

std::call_once 确保某个操作或函数仅执行一次,无论多少线程同时执行该操作。它会使用一个 std::once_flag 对象来标识该操作是否已经执行过。如果在多个线程中同时调用 std::call_once,只有第一个调用的线程会执行目标函数,其它线程会被阻塞,直到第一个线程执行完毕。

2. 语法

void std::call_once(std::once_flag& flag, Callable&& f, Args&&... args);
  • flag: 一个 std::once_flag 类型的对象,用来标识是否已经执行过目标函数。
  • f: 需要执行的目标函数(或可调用对象),可以是普通函数、函数指针、lambda 表达式等。
  • args…: 传递给目标函数的参数。

3. std::once_flag

std::once_flag 是一个特殊的对象,用来标记目标函数是否已经被调用过。它的生命周期应该和 std::call_once 调用相同,且通常会在程序的全局范围内或某个共享资源中声明。

4. 工作原理

std::call_once 确保目标函数只执行一次,即使有多个线程同时调用。在第一次调用时,目标函数会被执行;随后调用 std::call_once 的线程会被阻塞,直到第一次调用完成。

5. 示例

5.1 简单示例

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

std::once_flag flag;

void print_hello() {
    std::cout << "Hello, world!" << std::endl;
}

void thread_function() {
    std::call_once(flag, print_hello);
}

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;
}

在这个示例中,尽管有 3 个线程调用 std::call_once,但是 print_hello() 只会执行一次,输出为:

Hello, world!

5.2 延迟初始化

std::call_once 常用于延迟初始化场景,比如在单例模式中初始化资源。

#include <iostream>
#include <mutex>

std::once_flag flag;

void initialize() {
    std::cout << "Initialization done." << std::endl;
}

void do_work() {
    std::call_once(flag, initialize); // 确保只执行一次初始化
    std::cout << "Work is done." << std::endl;
}

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

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

    return 0;
}

在这个示例中,initialize() 函数只会被调用一次,即使有多个线程尝试执行它。

6. 应用场景

  • 单例模式(Singleton Pattern):确保在多线程环境下,单例对象只初始化一次。
  • 延迟初始化(Lazy Initialization):在程序启动时并不立即初始化某个资源,而是等到真正需要时再初始化,而且确保这个初始化操作只发生一次。
  • 初始化共享资源:多个线程可能需要初始化某个共享资源,使用 std::call_once 可以保证该资源只会初始化一次。

7. 线程安全性

std::call_once 是线程安全的,它保证了多个线程同时调用时只会有一个线程成功执行目标函数。其他线程会被阻塞直到第一个线程完成执行。

8. 注意事项

  • std::call_once 的目标函数(即传给它的可调用对象)必须是 幂等 的,即函数应该能安全地多次执行,而不会产生副作用(在某些情况下,可能会多次调用 std::call_once,但每次调用目标函数之前都会被阻塞)。
  • 不能在目标函数中使用会导致死锁的操作,因为其他线程会在目标函数未执行完时被阻塞。

总结

std::call_once 是 C++11 提供的一个线程安全的机制,能够确保某个函数在多个线程中只执行一次。它通常与 std::once_flag 一起使用,用于实现线程安全的初始化、单例模式和延迟初始化等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Liknana

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

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

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

打赏作者

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

抵扣说明:

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

余额充值