c++中的 单例模式(singleton)和双检测锁(Double-Checked Locking)

C++单例模式线程安全实现:从原理到Meyers‘ Singleton最佳实践 在C++多线程编程中,设计模式的选择直接影响程序的稳定性和性能。单例模式作为一种创建型模式,其核心目标是确保一个类只有一个实例并提供全局访问点。然而,在多线程环境下,实例的创建过程可能因并发访问而引发线程安全问题,例如多次初始化或返回未完全构造的对象。这涉及到C++内存模型、指令重排序以及编译器的优化行为。理解这些底层原理对于实现线程安全的单例至关重要,它能避免数据竞争、资源浪费乃至程序崩溃,是构建健壮后端服务的基础。C++11标准通过规定静态局部变量的线程安全初始化,为此提供了语言级别的支持。在实际应用场 阅读详情

懒汉式实现的单例模式
上文中给出的懒汉式实现的单例模式,在单线程中使用时完全没有问题的,但是在多线程中使用会存在多次对象多次创建的问题。

  1. 线程A进入getInstance方法,并进入到if判断,因为现在m_psl是空指针,这时刚好线程A时间片用完,开始切换到线程B,线程B也调用getInstance方法创建了一个对象
  2. 线程B时间片用完,切换到线程A,这时线程A从if判断成功之后的下不开始,又创建了一遍对象,这时已经两次创建对象了

为了解决这个问题需要使用双检测,详情可参考
C++ and the Perils of Double-Checked Locking
里面详细说明了双重检测的方法,和最终的解决方案。

要想解决上述懒汉单例模式中的问题,需要引入这个双重检测的功能,实现也只需将图中的代码在加锁的基础上,在添加一层检测

临界区(Critical Section)。临界区对象通过提供一个进程内所有线程必须
共享的对象来控制线程。只有拥有那个对象的线程可以访问保护资源。在另一个线
程可以访问该资源之前,前一个线程必须释放临界区对象,以便新的线程可以索取对象的访问权

最终实现效果如下

if (m_psl == NULL)
{
	// 这里线程开始资源竞争,只有一个线程能获取lock的资源
	lock();
	if (m_psl == NULL)
	{
		m_psl = new Singelton;
	}
	unlock();
}

说明:
lock里面判断一次,因为可能有多个线程在lock处等待,一个成功之后,会将m_psl设置为非空,这样下个线程就算拿到lock资源,再进去发现指针非空就离开了
lock外判断一次,是因为获取锁,是很浪费时间的,获取锁之外还有一层判断,那么在第二次获取单例对象的时候,lock外的if判断发现指针已经非空,就不会再获取锁了,直接返回了对应的对象,这样双层检测,即保证了对象创建的唯一性,又减少了获取锁浪费的时间和资源

不安全的单例模式代码:

#include <iostream>
using namespace std;


//懒汉式
class Singelton
{
private:
	Singelton()
	{
		cout << "Singelton 构造函数执行" << endl;
	}
public:
	static Singelton *getInstance()
	{
		if (m_psl == NULL)
		{
			m_psl = new Singelton;
		}
		return m_psl;
	}

	static void FreeInstance()
	{
		if (m_psl != NULL)
		{
			delete m_psl;
			m_psl = NULL; 
		}
	}

private:
	static Singelton *m_psl;
};

Singelton *Singelton::m_psl = NULL;


void main041()
{
	
	Singelton *p1 = Singelton::getInstance();
	Singelton *p2 = Singelton::getInstance();

	if (p1 == p2)
	{
		cout << "是同一个对象" << endl;
	}
	else
	{
		cout << "不是同一个对象" << endl;
	}
	Singelton::FreeInstance();

	
	return ;
}
C++ Singleton深度解析:保护、重用与生存期管理 Singleton(单例模式)是面向对象编程中基础而关键的创建型设计模式,其核心在于确保一个类仅有一个实例并提供全局访问点。它涉及构造控制、拷贝/移动语义约束、线程安全初始化及析构时机管理等底层原理。技术价值体现在对全局状态的可控封装、资源复用效率提升以及跨模块生命周期协同;典型应用场景包括日志管理器、配置加载器、数据库连接池等需强一致性和唯一性的系统服务。本文聚焦C++语言特性下的Singleton实现本质,深入剖析构造函数私有化、CRTP继承陷阱、std::call_once线程安全机制、atexit销 阅读详情

相关推荐

Ubuntu操作系统等保测评指南

Ubuntu操作系统等保测评指南

qq_40181198的博客 7025

C++并发多线程--单例设计模式和双重检查锁

这时候若其他线程发现了单例对象已被创建(已有地址空间),就可能会选择调用类对象的成员函数(但这时复杂的成员函数未初始化),就会出现错误;若一个类对象比较复杂和庞大,并且是可以复用的,当频繁地去创建和销毁类对象时就会造成巨大的性能浪费,通过单例设计模式将这个类对象设计为单例对象可以解决上述问题;双重检查锁可以避免多个线程发生数据竞争的情况,在下面的代码中使用双重检查锁可以避免多个线程同时创建类对象的情况(即执行 new MyCAS();3--std::call_once()的使用。(当需要实例时才去加载);

牵一只蜗牛去散步 1002

告别裸机SPI!用HAL库和CubeMX重新玩转STM32与MAX6675温度传感器

本文详细介绍了如何利用STM32CubeMX和HAL库高效驱动MAX6675温度传感器,实现稳定可靠的热电偶温度监测系统。通过图形化配置SPI接口和封装专用驱动函数,开发者可以快速构建嵌入式温度测量方案,适用于工业控制、物联网设备等多种应用场景。

weixin_42525632的博客 234

C++单例的安全实现,double-check(双重检查锁定)的安全实现方法

本文使用C++11 实现饿汉式和懒汉式单例,包括double-check

Where there is life, there is hope. 4757

常见的数值积分方法 (欧拉、中值、龙格-库塔,【常用于IMU中】)

1. 积分基本概念 设F(x)为函数f(x)的一个原函数,我们把函数f(x)的所有原函数F(x)+C(C为任意常数)叫做函数f(x)的不定积分(indefiniteintegral)。 非线性微分方程: 在有限的时间间隔Δt积分: 连续时间内积分: 工程上最常见的有三种:欧拉积分(Euler method)、中值积分(Midpoint method)和龙格-库塔法积分(Runge–Kutta methods)。他们的区别就是如何用数值方法模拟一个斜率。这里简单总结如下: ...

努力努力努力 2万+

解决windows10下无法安装.net framework 3.5(包括.net2.0和3.0)

入域电脑,win10系统中安装 .net framework 3.5(包括.net2.0和3.0)

God_me_1的博客 4万+

双检加锁机制

尽管双重检查锁定在性能上有一定的优势,但也需要小心使用,因为它在一些早期版本的Java中存在一些问题,如指令重排问题。因此,在现代Java版本中,可以考虑使用其他线程安全的延迟初始化方法,如静态内部类或枚举类型单例,以避免潜在的问题。

m0_54187478的博客 2309

【ARM Trace32(劳特巴赫) 使用介绍 10 -- Trace32 scan dump 详细介绍】

将图 1-2 中扫描单元按照扫描移位模式连接起来,就构成了扫描测试中的基本结构,这里介绍下全扫描。全扫描就是多个扫描单元相连接,上一单元的扫描输出,连接到目前单元的扫描输入,目前单元的扫描输出连接到下一单元的扫描输入,以此类推,构成一条移位寄存器链,如图1-3 所示:图 1-3 全扫描这样的扫描结构,可通过一个串行输入端,将期望的数据存入移位寄存器链并观察运行结果。

CodingCos的博客 2033

C++和双重检查锁定的危险

C++和双重检查锁定的危险1 简介2 单例模式和多线程3 双重检查锁定模式 多线程只是之后、之前或同时的一件事和另外一个。 1 简介 在Google新闻组或网络上搜索各种设计模式的名称,您肯定会发现最常提到的一种是 Singleton。但是,尝试将 Singleton 付诸实践,您几乎肯定会遇到一个重要的限制:按照传统实现(以及我们在下面解释的),Singleton 不是线程安全的。 已经付出了很多努力来解决这个缺点。最流行的方法之一是其自身的设计模式,即双重检查锁定模式 (DCLP) [13,

weixin_43488529的博客 1194

Python爬虫实战:使用最新技术抓取采购网招标公告信息

本文将详细介绍如何使用Python最新爬虫技术构建一个高效的采购网招标公告信息抓取系统。我们将从爬虫基础概念讲起,逐步深入到高级技巧,包括异步处理、反爬虫对策、数据解析与存储等,并提供完整的代码实现。本文旨在为读者提供一套完整的网络数据采集解决方案,适用于各类政府采购平台和商业招标网站。网络爬虫(Web Crawler)是一种自动抓取互联网信息的程序或脚本,它们按照一定的规则,自动地浏览万维网并提取所需数据。在现代商业环境中,爬虫技术广泛应用于价格监控、竞争情报收集、市场研究等领域。

2201_76125261的博客 1620

将指定文件夹下每张用LabelImg标注的图片中标注部分抠出来保存到指定文件夹下。

将指定文件夹下每张用LabelImg标注的图片中标注部分抠出来保存到指定文件夹下。

weixin_44119674的博客 440

C++11 修复了DCL双重检查锁定问题

转自http://developer.51cto.com/art/201311/419604.htm 双重检查锁定模式(DCLP)在无锁编程(lock-free programming)中经常被讨论,直到2004年,JAVA才提供了可靠的双重检查锁定实现。而在C++11之前,C++没有提供一种该模式的可移植的可靠实现。 随着双重检查锁定模式在各语言实现上存在的缺点暴露,人们开始研究如何

janeqi1987的专栏 3019

如何使用freesurfer对T1w结构像进行分区指标的提取?——皮层面积,灰质体积,平均厚度,厚度标准差,平均曲率、高斯曲率、曲率指数、折叠指数

如何使用freesurfer对T1w结构像进行分区指标的提取?——皮层面积,灰质体积,平均厚度,厚度标准差,平均曲率、高斯曲率、曲率指数、折叠指数

从事脑科学核磁共振方法学研究,在Nature communications等权威期刊发表研究论文,熟练掌握磁共振处理方法和统计学方法,欢迎大家和我交流。 3787

单例模式singleton及双检锁double-checked locking

[color=red]饿汉式单例类[/color] [code="java"] public class Singleton { private Singleton(){ } private static Singleton instance = new Singleton(); private static Singleton getInstance(){ ...

iteye_7957的博客 218

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

【线程安全】—— 单例类双重检查加锁(double-checked locking)

1. 三个版本单例类的实现 版本1:经典版public class Singleton { public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance;

1523

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

C++和双检锁的风险

本篇文章介绍了为什么在c++11之前使用单例模式的双检测锁写法会出问题。以及在c++11中怎么解决的这些问题。第一篇论文主要讨论了为什么会出问题,第二篇论文讨论了怎么利用c++11来解决这些问题。如果有翻译不确定的地方放上了原文供大家参考。   文章目录 C++ 和双检锁的风险(C++ and the Perils of Double-Checked Locking)介绍单例模式与多线程双重检查锁定模式DCLP与指令排序 C++11 中的双重检查锁定模式(Double-Chec.

小胖七少爷的博客 990

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

DCL(双检测锁定-Double Checked Lock)安全性分析(转)

在水木上看到一篇分析DCL(双检测锁定-Double Checked Lock)安全性的文章。记得以前也讨论过这个问题,但是为什么DCL也存在隐患,至今没弄明白,这篇分析做了比较详尽的解释,概括起来原因有两点:一是因为编译器或者处理器并不是严格按照程序顺序进行指令调度。二是java中同步机制的存在。 原文来自: 发信人: wyxzellux (I still believe...), 信区:

八荒六合唯我独尊 2547

double-check

ACE_Singleton 的 instance的实现: template TYPE * ACE_Singleton::instance (void) { ACE_TRACE ("ACE_Singleton::instance"); ACE_Singleton *&singleton = ACE_Singleton::instance_i (); // Perfor

人体运动、生物特征、高性能移动计算、人性化智能交互 1174

C++单例模式:从线程安全到现代实现与替代方案

在软件设计中,设计模式是解决常见问题的可复用方案,其中单例模式用于确保类只有一个实例并提供全局访问点。其原理是通过私有化构造函数和静态方法控制实例化过程,从而避免多实例导致的资源冲突。这一模式在管理全局资源如配置、日志系统时具有重要技术价值,能有效解决资源唯一性需求。然而,单例模式也常因引入全局状态而被视为反模式,可能影响代码可测试性。在实际应用场景中,现代C++通过局部静态变量、std::call_once等机制实现线程安全,同时依赖注入等替代方案能更好地满足复杂项目的需求。本文以日志系统为例,探讨了单例

weixin_30721077的博客 377

C++单例模式深度解析:从线程安全到现代实现与框架应用

单例模式是一种创建型设计模式,其核心原理是通过私有化构造函数和静态访问方法,确保一个类在整个应用程序生命周期中仅有一个实例。这一机制在资源共享、状态统一管理和避免重复创建开销等场景中具有重要技术价值,尤其适用于配置管理器、日志系统、数据库连接池等需要全局唯一访问点的组件。在多线程环境下,单例模式的线程安全实现成为关键挑战,涉及双重检查锁定、内存序等底层概念。随着现代C++标准的发展,局部静态变量初始化、std::call_once等特性提供了更优雅的解决方案。在框架开发中,单例模式常被用于消息总线等核心基础

weixin_34268843的博客 352

C++单例模式全解析:从懒汉式到Meyers‘ Singleton的线程安全之路

设计模式是软件工程中反复验证的解决方案模板,单例模式作为其中最具代表性的一种,旨在确保全局唯一实例并统一访问入口。然而在C++中实现单例远比Java等语言复杂:C++11之前缺少跨线程的静态初始化保证,对象生命周期又完全由开发者掌控,导致懒汉式、饿汉式、双重检查锁等经典写法在不同场景下各有隐患。技术价值在于合理管理配置管理器、日志输出器、数据库连接池等全局共享资源,避免状态不一致与资源泄漏。应用实践中,多线程环境必须关注初始化竞态、指令重排、析构顺序等深层问题,现代C++推荐使用局部静态变量实现的Meyer

weixin_33896726的博客 401

设计模式系列之单例模式

单例模式是使用最广泛,也最简单的设计模式之一,作用是保证一个类只有一个实例。单例模式是对全局变量的一种改进,避免全局变量污染命名空间。因为以下几个原因,全局变量不能作为单例的实现方式: 1. 不能保证只有一个全局变量 2. 静态初始化时可能没有足够的信息创建对象 3. c++中全局对象的构造顺序是未定义的,如果单件之间存在依赖将可能产生错误 单例模式的实现代码很简单:

103

C++11单例模式现代化改造:线程安全、懒加载与资源管理

单例模式是软件设计中用于确保类只有一个实例的创建型模式,其核心原理是通过控制实例化过程来提供全局访问点。在C++11之前,实现线程安全的懒加载单例常面临双重检查锁定的内存重排和静态初始化顺序等难题。C++11引入的内存模型、std::call_once及局部静态变量线程安全初始化等特性,从根本上解决了这些并发安全问题,使单例模式能够以更简洁、健壮的方式实现。这些改进不仅提升了代码的可靠性,还通过智能指针优化了资源管理,避免了手动内存管理的风险。在现代高并发服务器、框架核心模块等场景中,安全高效的单例实现尤为

weixin_33895516的博客 460

SGS-SLAM源码架构完整导读:scripts、utils与datasets核心模块全解析

SGS-SLAM(Semantic Gaussian Slatting For Neural Dense SLAM)是 ECCV 2024 提出的**首个基于 3D 高斯泼溅的语义视觉 SLAM 系统**:它通过多通道优化同时恢复相机位姿、3D 几何与语义信息,实现实时渲染与物体级分割。本文面向新手,带你读懂 SGS-SLAM 源码架构,重点解析 `scripts`、`utils` 与 `data

gitblog_00159的博客 267

C++原子操作内存序实战:从自旋锁到无锁计数器的性能优化

在多线程编程中,数据竞争是导致程序行为不确定性的常见问题。C++11引入的原子操作和内存模型为解决此问题提供了基础工具,其中内存序(Memory Ordering)是确保操作可见性和顺序一致性的核心机制。它定义了线程间内存操作的可见顺序,直接影响程序的正确性与性能。通过合理选择内存序,开发者可以在保证线程安全的前提下,最大化并发性能。本文聚焦于C++原子操作的内存序实战应用,深入探讨了自旋锁实现、无锁计数器等典型场景中不同内存序的选择策略与性能影响。例如,在实现自旋锁时,使用`acquire-release

wjxbj的博客 441
上一篇: 23种设计模式C++源码与UML实现--单例模式中的饿汉模式和懒汉模式
下一篇: 23种设计模式C++源码与UML实现--简单工厂模式
andrewbytecoder
andrewbytecoder 领域专家: C/C++技术领域 领域专家: C/C++技术领域
博客等级 码龄10年 3476粉丝 687原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

andrewbytecoder

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值