【C++11 之单例模式线程安全原理+案例】及旧版本互斥锁线程安全案例

在C++11及之后的版本中,当函数返回局部静态变量时,该变量的初始化是线程安全的。

浅层原理

这是因为C++11标准引入了“魔术静态局部变量”(Magic Static Locals)的概念,它确保了在多线程环境中,局部静态变量的初始化只会被执行一次,并且这个初始化过程是线程安全的。

在单例模式中,通常会看到一个私有的静态成员变量和一个公有的静态成员函数get_instance()来返回这个私有静态成员变量的引用或指针。在C++11之前,这种懒汉式单例实现通常需要使用互斥锁(如pthread_mutex_t或std::mutex)来确保线程安全。但在C++11及之后,你可以简单地通过返回一个局部静态变量的引用来实现线程安全的单例。

深层原理

在C++11中,编译器和运行时库合作来确保局部静态对象的线程安全初始化,但是具体的实现细节是依赖于编译器和平台的。不过,从概念上讲,我们可以大致理解编译器是如何判断“第一次”和“后续次”调用的。

  1. 编译时标记:编译器在编译时识别出函数中的静态局部对象,并标记这个对象需要特殊的初始化处理。这个标记可能是一个标志,指示运行时库在第一次调用该函数时进行初始化。
  2. 运行时检查:当函数被调用时,运行时库会检查该静态局部对象是否已经被初始化。这通常是通过检查一个与静态局部对象相关联的标志位来实现的。这个标志位可能在静态对象的内存区域附近或者在某个专门的区域中。
  3. 初始化锁:如果运行时库发现静态对象尚未初始化,它会使用一个锁(例如互斥锁)来确保只有一个线程可以执行初始化代码。这个锁保证了同一时间只有一个线程可以访问初始化代码段。
  4. 执行初始化:获得锁的线程将执行静态对象的初始化代码。这可能包括调用构造函数、分配内存等。
  5. 设置已初始化标志:一旦初始化完成,运行时库将设置与静态对象相关联的标志位,表示该对象已经初始化。
  6. 后续调用:当其他线程调用该函数时,运行时库会检查已初始化标志。由于这个标志已经设置,运行时库知道静态对象已经初始化,因此它不会再次执行初始化代码,而是直接返回对象的引用或指针。
  7. 锁的释放:获得锁的线程在初始化完成后会释放锁,允许其他线程继续执行。

此外,C++标准并没有规定具体的实现细节,所以不同的编译器和平台可能会有不同的实现方式。但是,它们都必须遵守C++11标准对线程安全初始化的要求。

以下是一个C++11线程安全单例模式的简单示例:

class Singleton {  
public:  static Singleton& get_instance() {  static Singleton instance; // C++11中局部静态变量初始化是线程安全的  return instance;  }  // 其他成员函数和私有构造函数...  private:  Singleton() {} // 私有构造函数,防止外部直接创建实例  Singleton(const Singleton&) = delete; // 禁止拷贝构造函数  Singleton& operator=(const Singleton&) = delete; // 禁止拷贝赋值操作符  
};

在这个示例中,get_instance()函数返回了一个对Singleton类型局部静态成员变量instance的引用。由于这个局部静态变量是在函数内部声明的,并且只在第一次调用get_instance()时被初始化,因此它的初始化过程是线程安全的。此后,所有对get_instance()的调用都将返回对同一个Singleton实例的引用。

这种线程安全的单例实现方式被称为“Meyers’ Singleton”(以Scott Meyers命名,他在其著作《Effective C++》中介绍了这种方法)。在C++11及之后的版本中,它被广泛用于实现线程安全的单例。

在C++11之前,单例模式的线程安全通常是通过以下几种方式保障的:

C++11之前的单例模式主要通过互斥锁、双重检查锁定、饿汉式单例模式和使用其他同步机制来保障线程安全。然而,这些方法各有优缺点,需要根据具体的应用场景和需求来选择合适的方法。

互斥锁实现单例模式线程安全案例:

在C++11之前,通常我们会使用互斥锁(如pthread_mutex_t在POSIX线程中,或者在C++标准库中使用std::mutex,尽管std::mutex是C++11引入的,但这里我们可以假设我们有一个兼容的互斥锁实现)来保证单例模式的线程安全。以下是一个使用pthread_mutex_t的示例:

#include <pthread.h>  class Singleton {  
private:  static Singleton* instance;  static pthread_mutex_t mutex;  Singleton() {} // 私有构造函数,防止外部直接创建实例  Singleton(const Singleton&) = delete; // 禁止拷贝构造函数  Singleton& operator=(const Singleton&) = delete; // 禁止拷贝赋值操作符  public:  static Singleton* getInstance() {  pthread_mutex_lock(&mutex); // 加锁  if (instance == nullptr) {  instance = new Singleton();  }  pthread_mutex_unlock(&mutex); // 解锁  return instance;  }  // 析构函数应为私有且为删除操作,确保单例对象在程序结束时正确销毁  // 这里为了简化示例,我们省略了析构函数的细节和单例的销毁逻辑  // ~Singleton() { /* ... */ }  // 其他成员函数...  
};  // 静态成员初始化  
Singleton* Singleton::instance = nullptr;  
pthread_mutex_t Singleton::mutex = PTHREAD_MUTEX_INITIALIZER;  // 注意:在程序结束时,需要确保正确销毁单例实例和互斥锁  
// 这通常通过注册一个atexit函数或使用其他机制来完成  // 示例使用  
int main() {  Singleton* s1 = Singleton::getInstance();  Singleton* s2 = Singleton::getInstance();  // s1 和 s2 指向同一个实例  // ...  return 0;  
}

请注意,在上面的代码中,我们使用了pthread_mutex_t作为互斥锁,并使用pthread_mutex_lock和pthread_mutex_unlock函数来加锁和解锁。此外,instance和mutex都被声明为静态成员变量,以确保它们在类的所有实例之间共享。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/862916.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第1章_搭建开发环境

文章目录 第1章 搭建开发环境1.1开发套件硬件接口资源介绍1.2资料下载1.3安装Keil MDK1.3.1**软件下载**1.3.2**软件安装**1.3.3 PACK 安装 1.4 安装 STM32CubeMX1.5 安装 STM32CubeProgrammer1.6 安装 ST-Link 驱动1.7 安装 CH340 驱动 第1章 搭建开发环境 1.1开发套件硬件接…

Dijkstra算法C代码

一个带权图n个点m条边&#xff0c;求起点到终点的最短距离 先定义一个邻接矩阵graph&#xff0c;graph[i][j]表示从i到j的距离&#xff0c;i到j没有路就表示为无穷 然后定义一个visit数组&#xff0c;visit[i]表示i结点是否被访问 然后定义一个dist数组&#xff0c;dist[i]表…

Redis基础教程(一):redis配置

&#x1f49d;&#x1f49d;&#x1f49d;首先&#xff0c;欢迎各位来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里不仅可以有所收获&#xff0c;同时也能感受到一份轻松欢乐的氛围&#xff0c;祝你生活愉快&#xff01; &#x1f49d;&#x1f49…

星光云720全景VR系统源码

星光云720全景VR系统源码 系统体验地址项目介绍JDK版本后端主要依赖前端框架前端node 版本用户端框架介绍技术选型依赖全景内容简介系统图片部分功能截图系统体验地址 系统体验地址 VR全景系统体验地址 账号&#xff1a;18175760278 密码&#xff1a;12345678 项目介绍 JDK版…

AudioLM: 音频生成模型

AudioLM: 音频生成模型 音频生成模型是一种利用人工智能技术生成声音或音频内容的模型。它利用深度学习技术,尤其是生成对抗网络(GANs)或变分自编码器(VAEs),结合声音合成和信号处理技术,从输入的文本、图像或其他形式的数据中生成音频。这些模型广泛应用于语音助手、游…

图鸟模板-官网:基于Vue 3的前端技术探索与实践

摘要&#xff1a; 随着Web技术的不断发展&#xff0c;前端开发已经从简单的页面展示向功能丰富、交互体验优良的方向发展。Vue.js作为一款轻量级且功能强大的前端框架&#xff0c;自推出以来就受到了广泛的关注和应用。特别是Vue 3的发布&#xff0c;更是为前端开发带来了诸多新…

机器学习笔记 人脸识别技术全面回顾和小结(1)

一、简述 人脸识别是视觉模式识别的一个细分问题。人类一直在识别视觉模式&#xff0c;我们通过眼睛获得视觉信息。这些信息被大脑识别为有意义的概念。对于计算机来说&#xff0c;无论是图片还是视频&#xff0c;它都是许多像素的矩阵。机器应该找出数据的某一部分在数据中代表…

最近公共祖先(倍增,tarjan,树链剖分)

两个点的最近公共祖先&#xff0c;即两个点的所有公共祖先中&#xff0c;离根节点最远的一个节点。 倍增算法 1.dfs一遍&#xff0c;创建ST表 2.利用ST表求LCA 内容来源 D09 倍增算法 P3379【模板】最近公共祖先&#xff08;LCA&#xff09; #include<iostream> #in…

特斯拉下一代自动驾驶芯片的深度预测

引言 特斯拉一直以来都在自动驾驶技术上不断突破&#xff0c;随着AI大模型技术的爆发&#xff0c;其下一代自动驾驶芯片&#xff08;HW5.0&#xff09;也备受瞩目。本文将深入分析和预测特斯拉下一代自动驾驶芯片AI5的技术特点及其对行业的影响。 深入技术分析 现有自动驾驶…

MySQL8.0新特性~General tablespaces

通用表空间创建语法 InnoDB and NDB:[ADD DATAFILE file_name][AUTOEXTEND_SIZE [] value]InnoDB only:[FILE_BLOCK_SIZE value][ENCRYPTION [] {Y | N}]NDB only:USE LOGFILE GROUP logfile_group[EXTENT_SIZE [] extent_size][INITIAL_SIZE [] initial_size][MAX_SIZE [] ma…

React小记(五)_Hooks入门到进阶

React 16.8 版本 类组件 和 函数组件 两种组件共存&#xff0c;到目前 React 18 版本&#xff0c;官方已经不在推荐使用类组件&#xff0c;在函数组件中 hooks 是必不可少的&#xff0c;它允许我们函数组件像类组件一样可以使用组件的状态&#xff0c;并模拟组件的生命周期等一…

用Python写一个基于ai agent服务scrm,mes和erp系统的协同流程

要实现一个基于AI Agent的协同流程&#xff0c;我们需要首先了解SCRM、MES和ERP系统的基本功能和相互之间的关系。然后&#xff0c;我们可以用Python编写一个简单的示例&#xff0c;展示这些系统如何协同工作。以下是一个基本的协同流程示例&#xff1a; 1. 假设我们有一个SCRM…

高效数据采集监控平台 一体化平台 数据可视化!

提高工作效率&#xff0c;一直是各种厂家在寻找的方法。任何一种有效且实用的方法都值得去尝试。数据采集监控平台是一种能高效处理数据的方式&#xff0c;其主要工作内容是从各个产生数据的仪器设备传感器中采集数据、对数据进行集中整理整合、分析、显示、绘制图表、存储、传…

java基于ssm+jsp 扶贫惠农推介系统

1管理员功能模块 管理员输入个人的用户名、密码、角色登录系统&#xff0c;这时候系统的数据库就会在进行查找相关的信息&#xff0c;如果我们输入的用户名、密码不正确&#xff0c;数据库就会提示出错误的信息提示&#xff0c;同时会提示管理员重新输入自己的用户名、密码&am…

DigiRL:让 AI 自己学会控制手机

类似于苹果此前发布的Ferret-UI 的安卓开源平替。主要用于在 Android 设备上识别 UI 和执行指令&#xff0c;不同的是它利用了离线到在线强化学习&#xff08;Offline-to-Online RL&#xff09;&#xff0c;能够快速适应应用更新或 UI 变化。

2023信息素养大赛国赛C++真题

2023信息素养大赛国赛C 第一题 给定一个五位数x&#xff0c;你需要重复做以下操作: 把数的各个数位进行由大到小排序和由小到大排序&#xff0c;得到的最大值和最小值&#xff0c;进行求差后作为新的x。 可以证明&#xff0c;在经过有限次操作后&#xff0c;x会循环出现。 …

总结:Hive

一、Hive介绍 Hive 是一个构建在 Hadoop 上的数仓工具&#xff0c;用于处理和查询存储在 HDFS 上的大规模数据。它使用类似 SQL 的 HiveQL 来执行查询&#xff0c;但背后是将查询任务转译成 MapReduce、Tez 或 Spark 等分布式计算任务来执行。Hive 的主要优势包括&#xff1a;…

麒麟桌面系统CVE-2024-1086漏洞修复

原文链接&#xff1a;麒麟桌面操作系统上CVE-2024-1086漏洞修复 Hello&#xff0c;大家好啊&#xff01;今天给大家带来一篇在麒麟桌面操作系统上修复CVE-2024-1086漏洞的文章。漏洞CVE-2024-1086是一个新的安全漏洞&#xff0c;如果不及时修复&#xff0c;可能会对系统造成安全…

LeetCode:2710. 移除字符串中的尾随零

题目 给你一个用字符串表示的正整数 num &#xff0c;请你以字符串形式返回不含尾随零的整数 num 。 示例 1&#xff1a; 输入&#xff1a;num “51230100” 输出&#xff1a;“512301” 解释&#xff1a;整数 “51230100” 有 2 个尾随零&#xff0c;移除并返回整数 “51230…

Spring MVC中使用ModelAndView传递数据

Spring MVC中使用ModelAndView传递数据 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天我们来探讨在Spring MVC中如何使用ModelAndView来传递数据。ModelAn…