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

news/2025/2/8 18:46:37/

目录

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/news/1570381.html

相关文章

第30节课:前端架构与设计模式—构建高效可维护的Web应用

目录 前端架构设计前端架构的重要性前端架构设计原则模块化可维护性可扩展性性能优化 前端架构设计方法MVC&#xff08;Model-View-Controller&#xff09;MVVM&#xff08;Model-View-ViewModel&#xff09;单页应用&#xff08;SPA&#xff09; 设计模式在前端的应用设计模式…

PHP-综合3

[题目信息]&#xff1a; 题目名称题目难度PHP-综合32 [题目考点]&#xff1a; PHP综合训练[Flag格式]: SangFor{IoOvaUFeUjE1Lt2hatHL_z9uKyTLu0Cn}[环境部署]&#xff1a; docker-compose.yml文件或者docker tar原始文件。 http://分配ip:2047[题目writeup]&#xff1a;…

Oracle迁移到MySQL

Oracle迁移到MySQL业务需要全面改造适配&#xff0c;数据库对象和业务SQL语法需要一对一映射分析如何改写&#xff0c;根据业务使用实际情况评估改造适配成本较高。 目前&#xff0c;已有数据库产品能力缺少自动化迁移工具&#xff0c;需要依赖生态产品能力&#xff0c;比如云和…

leetcode_78子集

1. 题意 给定一个不含有重复数字的数列&#xff0c;求所有的子集。 2. 题解 子集型回溯&#xff0c;可以直接用dfs进行搜索&#xff1b;也可以用二进制来进行枚举。 2.1 选或不选 class Solution { public:void dfs(vector<vector<int>> &ans,vector<i…

Swipe横滑与SwipeItem自定义横滑相互影响

背景 vue项目&#xff0c;H5页面&#xff0c;使用vant的组件库轮播组件<Swipe>&#xff0c;UI交互要求&#xff0c;在每个SwipeItem中有内容&#xff0c;可自横滑&#xff0c;查看列表内容 核心代码 <template><Swipeclass"my_swipe":autoplay&quo…

tcp/ip网络协议,tcp/ip网络协议栈

TCP/IP网络协议和TCP/IP网络协议栈是互联网通信的基石&#xff0c;它们定义了电子设备如何连入因特网以及数据如何在它们之间传输的标准。以下是对TCP/IP网络协议和TCP/IP网络协议栈的详细解释&#xff1a; 一、TCP/IP网络协议 TCP/IP&#xff08;Transmission Control Proto…

科技赋能数字内容体验的核心技术探索

内容概要 在数字化时代&#xff0c;科技的迅猛发展为我们的生活和工作带来了深刻的变革。数字内容体验已经成为人们获取信息和娱乐的重要途径&#xff0c;而这背后的技术支持则扮演着至关重要的角色。尤其是在人工智能、虚拟现实和区块链等新兴技术的推动下&#xff0c;数字内…

硬件电路基础

目录 1. 电学基础 1.1 原子 1.2 电压 1.3 电流 1.电流方向&#xff1a; 正极->负极,正电荷定向移动方向为电流方向&#xff0c;与电子定向移动方向相反。 2.电荷&#xff08;这里表示负电荷&#xff09;运动方向&#xff1a; 与电流方向相反 1.4 测电压的时候 2. 地线…