当前位置: 首页 > article >正文

高阶开发基础——快速入门C++并发编程4

目录

使用call_once来确保调用的唯一性

先看我们的原始的单例模式


使用call_once来确保调用的唯一性

一个相似的概念是——单例模式,笔者找到的是stack_overflow的一个问答,如果不喜欢看英文,可以考虑看一下这个CSDN回答:

c++ - How do you implement the Singleton design pattern? - Stack Overflow

【C++】C++ 单例模式总结(5种单例实现方法)_单例模式c++实现-CSDN博客

总而言之,单例模式就是保证在多线程中对象的唯一性。C++11预料了这样的场景,因为十分多见(比如说初始化日志和初始化单一数据库等等)

所以,call_once就被用来保证在多个线程中只执行一次的用法。

先看我们的原始的单例模式

#include <cstdio>
#include <print>
#include <mutex>
​
class Logger;
Logger* global_logger_instance = nullptr;
​
class Logger
{
public:
    // disable the copy
    Logger(const Logger&) = delete;
    Logger& operator=(const Logger&) = delete;
​
    static Logger& instance(){
        __pvt_init();
        return *global_logger_instance;
    }
​
    static void write_logger(const std::string& info){
        std::print("{}\n", info);
    }
​
private:
    static void __pvt_init(){
        if(!global_logger_instance){
            global_logger_instance = new Logger;
            std::print("Logger is inited for once\n");
        }
    }
    Logger() = default;
};
​
void make_logging()
{
    Logger::instance().write_logger("hello");
    Logger::instance().write_logger("world");
    Logger::instance().write_logger("It can be promised");
    Logger::instance().write_logger("that the logger written only");
    Logger::instance().write_logger("once!");
}
​
​
int main()
{
    make_logging();
}

这是一种,非常线程不安全的实现,虽然这个代码在单线程中显然可以正确的工作,但是遗憾的是,只要放到多线程中,我们的初始化就会出现问题,很有可能导致潜在的双重初始化!

所以,办法就是请出我们的call_once来解决我们多线程单一执行问题:

#include <cstdio>
#include <print>
#include <mutex>
#include <thread>
class Logger;
Logger* global_logger_instance = nullptr;
std::once_flag promising_flag;
​
class Logger
{
public:
    // disable the copy
    Logger(const Logger&) = delete;
    Logger& operator=(const Logger&) = delete;
​
    static Logger& instance(){
        std::call_once(promising_flag, __pvt_init);
        return *global_logger_instance;
    }
​
    static void write_logger(const std::string& info){
        std::print("{}\n", info);
    }
​
private:
    static void __pvt_init(){
        if(!global_logger_instance){
            global_logger_instance = new Logger;
            std::print("Logger is inited for once\n");
        }
    }
    Logger() = default;
};
​
void make_logging()
{
    Logger::instance().write_logger("hello");
    Logger::instance().write_logger("world");
    Logger::instance().write_logger("It can be promised");
    Logger::instance().write_logger("that the logger written only");
    Logger::instance().write_logger("once!");
}
​
​
int main()
{
    std::thread pools[20];
    for(int i = 0; i < 20; i++){
        pools[i] = std::thread{make_logging};
    }
​
    for(int i = 0; i < 20; i++){
        pools[i].join();
    }
}

现在,我们创建若干的线程并不会发生多重初始化的问题!


http://www.kler.cn/a/530788.html

相关文章:

  • 【memgpt】letta 课程1/2:从头实现一个自我编辑、记忆和多步骤推理的代理
  • GESP2023年9月认证C++六级( 第三部分编程题(2)小杨的握手问题)
  • 实现使用K210单片机进行猫脸检测,并在检测到猫脸覆盖屏幕50%以上时执行特定操作
  • 54. 螺旋矩阵
  • ArkTS语言介绍
  • 增删改查(CRUD)操作
  • VU~大数据知识点总结
  • Vue06
  • 在vue中使用jsx
  • Flask代码审计实战
  • 洛谷P11655「FAOI-R5」Lovely 139
  • WPF进阶 | WPF 样式与模板:打造个性化用户界面的利器
  • 大厂面试题备份20250201
  • open-webui报错Connection to huggingface.co timed out.
  • TypeScript (TS) 和 JavaScript (JS)
  • 使用istio实现权重路由
  • DeepSeek发布新模型,遭遇大规模攻击,梁文锋回应证实为假,吴恩达盛赞DeepSeek!AI Weekly 1.27-2.2
  • NetLify账号无法登录解决办法
  • 网络测试-笔记
  • 【C++】线程池实现
  • fpga系列 HDL:XILINX Vivado 常见错误 “在线逻辑分析Debug时ALL_CLOCK没有选项”
  • Rust语言进阶之文件处理:BufReader用法实例(一百零三)
  • React常见状态管理工具详解
  • 【数据结构】(4) 线性表 List
  • 【数据结构-字典树】力扣211. 添加与搜索单词 - 数据结构设计
  • 利用腾讯云cloud studio云端免费部署deepseek-R1