C++多线程编程——call_once和单例模式

devtools/2025/2/6 21:23:04/

目录

1. 前言

2. call_once和once_flag

3. 后记

3.1 单例类的析构问题

3.2 饿汉式单例模式的线程安全问题


1. 前言

之前在讲解单例模式时,有提到懒汉式单例模式使用了双重检测Double-Checked Locking Pattern (DCLP)来解决多线程的安全访问问题。但是该方法也存在安全隐患

双重检查之所以有问题,是因为CPU会进行指令重排序。
instance = new Singleton;这条语句 一般会理解为构造一个对象并初始化后,然后赋值给instance 。
但是实际上CPU有可能先构造一个空对象 ,把这个空对象的地址赋值给instance , 最后才调用构造函数进行初始化。如果在调用构造函数对这片内存进行初始化之前发生了线程切换,另一个线程检查instance发现不为nullptr,进而使用instance,就会导致程序崩溃。

2. call_once和once_flag

在C++11中提供了call_once和once_flag,通过它们的配合使用,可以保证在多线程环境下某个可调用对象只执行一次。

这样,我们就可以把instance的初始化单独放到一个静态函数中,并通过call_once来执行。

具体请看以下代码:

#include <iostream>
#include <thread>using namespace std;class Singleton
{
private:static Singleton* instance;static once_flag init_flag;Singleton() = default;static void init_instance(){instance = new Singleton();}
public:~Singleton() = default;static Singleton* getInstance(){call_once(init_flag, &Singleton::init_instance);return instance;}
};Singleton* Singleton::instance = nullptr;
once_flag Singleton::init_flag;int main()
{Singleton* s1 = Singleton::getInstance();
}

3. 后记

3.1 单例类的析构问题

关于单例类的析构问题,可以采用之前介绍过的嵌套类的方式实现。也可以采用智能指针的方式实现,把instance类型改成shared_ptr<Singleton>,在静态对象消亡时,引用计数归零,会自动调用析构函数。

3.2 饿汉式单例模式的线程安全问题

在C++11之后,静态对象和全局对象的初始化一定是线程安全的,所以可以放心地使用。


http://www.ppmy.cn/devtools/156626.html

相关文章

数据结构(AVL树、B-Tree、B+Tree)

AVL树 AVL树是一种自平衡的二叉搜索树&#xff0c;它的特点是每个节点的左子树和右子树的高度差&#xff08;平衡因子&#xff09;的绝对值不超过1。这种平衡性保证了AVL树在进行查找、插入和删除操作时都能保持较高的效率。 平衡因子 在AVL树中&#xff0c;每个节点都维护一…

MySQL--》日志与主从复制的实战技巧

目录 日志 错误日志 二进制日志 查询日志 慢查询日志 主从复制 日志 日志&#xff1a;是记录数据库操作和事务的文件&#xff0c;主要用于帮助数据库管理员(DBA)跟踪、恢复数据以及进行故障排查&#xff0c;日志是MySQL数据库管理中非常重要的一部分&#xff0c;常见的日…

C基础寒假练习(2)

一、输出3-100以内的完美数&#xff0c;(完美数&#xff1a;因子和(因子不包含自身)数本身 #include <stdio.h>// 函数声明 int isPerfectNumber(int num);int main() {printf("3-100以内的完美数有:\n");for (int i 3; i < 100; i){if (isPerfectNumber…

【NLP251】NLP RNN 系列网络

NLP251 系列主要记录从NLP基础网络结构到知识图谱的学习 &#xff11;.原理及网络结构 &#xff11;.&#xff11;&#xff32;&#xff2e;&#xff2e; 在Yoshua Bengio论文中( http://proceedings.mlr.press/v28/pascanu13.pdf )证明了梯度求导的一部分环节是一个指数模型…

日本工作面试基本礼仪-一篇梗概

面接の内容に加えて、エチケットも非常に重要です。日本のビジネス社会には独自のビジネスマナー&#xff08;ビジネスマナー[ビジネスマナー]&#xff09;があり、国際基準とは異なる場合がありますので、注意が必要です。 日本人、特に日本の伝統的な大企業の面接官は、一般…

熟练掌握Http协议

目录 基本概念请求数据Get请求方式和Post请求方式 响应数据响应状态码 基本概念 Http协议全称超文本传输协议(HyperText Transfer Protocol)&#xff0c;是网络通信中应用层的协议&#xff0c;规定了浏览器和web服务器数据传输的格式和规则 Http应用层协议具有以下特点&#…

【开源免费】基于SpringBoot+Vue.JS美食推荐商城(JAVA毕业设计)

本文项目编号 T 166 &#xff0c;文末自助获取源码 \color{red}{T166&#xff0c;文末自助获取源码} T166&#xff0c;文末自助获取源码 目录 一、系统介绍二、数据库设计三、配套教程3.1 启动教程3.2 讲解视频3.3 二次开发教程 四、功能截图五、文案资料5.1 选题背景5.2 国内…

如何开发一个大语言模型,开发流程及需要的专业知识

开发大型语言模型&#xff08;LLM&#xff09;是一个复杂且资源密集的过程&#xff0c;涉及多个阶段和跨学科知识。以下是详细的开发流程和所需专业知识指南&#xff1a; 一、开发流程 1. 需求分析与规划 目标定义&#xff1a;明确模型用途&#xff08;如对话、翻译、代码生成…