高阶开发基础——快速入门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();
}
}
现在,我们创建若干的线程并不会发生多重初始化的问题!