【GeekBand】C++设计模式笔记12_Singleton_单件模式

1. “对象性能” 模式

  • 面向对象很好地解决了 “抽象” 的问题, 但是必不可免地要付出一定的代价。对于通常情况来讲,面向对象的成本大都可以忽略不计。但是某些情况,面向对象所带来的成本必须谨慎处理。
  • 典型模式
    • Singleton
    • Flyweight

2. Singleton 单件模式

2.1 动机(Motivation)

  • 在软件系统中,经常有这样一些特殊的类,必须保证它们在系统中只存在一个实例,才能确保它们的逻辑正确性以及良好的效率。
  • 如何绕过常规的构造器,提供一种机制来保证一个类只有一个实例?
  • 这应该是类设计者的责任,而不是使用者的责任。

2.2 模式定义

保证一个类仅有一个实例,并提供一个该实例的全局访问点
——《设计模式》GoF

2.3 实例代码

class Singleton {
private:
	// 将构造函数、拷贝构造函数设置成 private,不允许用户创建实例
    Singleton();
    Singleton(const Singleton& other);
    
public:
	// 提供实例的全局访问点
    static Singleton* getInstance();

private:
	// static 成员,唯一的实例
    static Singleton* m_instance;
};

// static 成员初始化
Singleton* Singleton::m_instance = nullptr;

/*
线程非安全版本,多线程环境下有可能创建出多个实例,
当线程A在执行完(1)、执行(2)之前,线程B抢到时间片,开始执行(1),这样线程A和B都可以创建出实例,
所以在多线程环境中需要加锁。
*/ 
Singleton* Singleton::getInstance() {
    if (m_instance == nullptr) {		// (1)
        m_instance = new Singleton();	// (2)
    }
    return m_instance;
}

/*
线程安全版本,但锁的代价过高,
因为锁的粒度粗,进入函数后立马加锁,整个函数过程都持有锁,
一般m_instance是只读的,当m_instance创建完成后,各线程可以直接获取该实例,
该代码既有问题:当线程A持有锁时,线程B无法获取m_instance,必须等待线程A释放锁。
*/
Singleton* Singleton::getInstance() {
    Lock lock;
    if (m_instance == nullptr) {
        m_instance = new Singleton();
    }
    return m_instance;
}

/*
双检查锁,但由于内存读写reorder不安全
reorder含义:编译器可能改变对象构造的顺序
常规对象构造分为3个步骤:a.分配空间;b.调用构造函数完成对象初始化;c.返回对象的指针;但编译器有时会改变这3个顺序,变成a.c.b。
这样代码就会出现问题:当m_instance未初始化时,线程A需要对m_instance进行实例化,若当线程A完成步骤a和c,而未完成b时,线程B调用该函数,由于此刻 m_instance != nullptr,会直接返回m_instance,但该实例尚未完成初始化,直接使用该实例会产生未定义行为。
(2)处的二次检查必不可少:当AB两个线程都通过(1)后开始抢锁,假设A抢到了锁,A对m_instance进行实例化,当线程A释放锁线程B获得锁后,如果没有(2)处的检查,线程B将再次对m_instance初始化,不符合单例模式设计原则。
*/
Singleton* Singleton::getInstance() { 
    if (m_instance == nullptr) {	// (1)
        Lock lock;
        if (m_instance == nullptr) {		// (2),这里的二次检查必不可少
            m_instance = new Singleton();	// (3)
        }
    }
    return m_instance;
}

// C++ 11版本之后的跨平台实现 (volatile)
std::atomic<Singleton*> Singleton::m_instance;
std::mutex Singleton::m_mutex;

Singleton* Singleton::getInstance() {
    Singleton* tmp = m_instance.load(std::memory_order_relaxed);
    std::atomic_thread_fence(std::memory_order_acquire);	// 获取内存fence
    if (tmp == nullptr) {
        std::lock_guard<std::mutex> lock(m_mutex);
        tmp = m_instance.load(std::memory_order_relaxed);
        if (tmp == nullptr) {
            tmp = new Singleton;
            std::atomic_thread_fence(std::memory_order_release);	// 释放内存fence
            m_instance.store(tmp, std::memory_order_relaxed);
        }
    }
    return tmp;
}

2.4 结构(Structure)

在这里插入图片描述

2.5 要点总结

  • Singleton 模式中的实例构造器可以设置为 protected 以允许子类派生。
  • Singleton 模式一般不要支持拷贝构造函数和 Clone 接口,因为这有可能导致多个对象实例,与 Singleton 模式的初衷违背。
  • 如何实现多线程环境下安全的 Singleton ?注意对双检查锁的正确实现。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

计算机网络 (1)互联网的组成

一、互联网的边缘部分 互联网的边缘部分由所有连接在互联网上的主机组成&#xff0c;这些主机又称为端系统&#xff08;end system&#xff09;。端系统可以是各种类型的计算机设备&#xff0c;如个人电脑、智能手机、网络摄像头等&#xff0c;也可以是大型计算机或服务器。端系…

电商行业客户服务的智能化:构建高效客户服务知识库

在电商行业&#xff0c;客户服务是提升用户体验和品牌忠诚度的关键。随着数字化转型的深入&#xff0c;构建一个高效的客户服务知识库变得尤为重要。本文将探讨电商行业如何构建客户服务知识库&#xff0c;并分析其在提升服务质量中的作用。 客户服务知识库的重要性 客户服务…

CentOS 9 无法启动急救方法

方法一&#xff1a;通过单用户安全模式启动 开机按上下方向键&#xff0c;选择需要启动的内核&#xff0c;按e键进入配置模式 修改配置 ro 改 rw 删除 rhgb quiet 末尾增加 init/bin/bash 按 Ctrlx 启动单用户模式 如果想重新启动&#xff0c;重启电脑 执行 exec /sbin/in…

数字后端零基础入门系列 | Innovus零基础LAB学习Day11(Function ECO流程)

###LAB 20 Engineering Change Orders (ECO) 这个章节的学习目标是学习数字IC后端实现innovus中的一种做function eco的flow。对于初学者&#xff0c;如果前面的lab还没掌握好的&#xff0c;可以直接跳过这节内容。有时间的同学&#xff0c;可以熟悉掌握下这个flow。 数字后端…

SAM-Med2D 训练完成后boxes_prompt没有生成mask的问题

之前对着这这篇文章去微调SAM_Med2D(windows环境),发现boxes_prompt空空如也。查找了好长时间问题SAM-Med2D 大模型学习笔记&#xff08;续&#xff09;&#xff1a;训练自己数据集_sam训练自己数据集-CSDN博客 今天在看label2image_test.json文件的时候发现了一些端倪: 官方…

java ssm 同仁堂药品管理系统 在线药品信息管理 医药管理源码jsp

一、项目简介 本项目是一套基于SSM的同仁堂药品管理系统&#xff0c;主要针对计算机相关专业的和需要项目实战练习的Java学习者。 包含&#xff1a;项目源码、数据库脚本、软件工具等。 项目都经过严格调试&#xff0c;确保可以运行&#xff01; 二、技术实现 ​后端技术&…

使用阿里云快速搭建 DataLight 平台

使用阿里云快速搭建 DataLight 平台 本篇文章由用户 “闫哥大数据” 分享&#xff0c;B 站账号&#xff1a;https://space.bilibili.com/357944741?spm_id_from333.999.0.0 注意&#xff1a;因每个人操作顺序可能略有区别&#xff0c;整个部署流程如果出现出入&#xff0c;以…

如何解决VS Code的Live Share会话中Guest无法看到共享的文件夹?

在 VS Code 的 Live Share 会话中&#xff0c;如果 Guest 无法看到共享的文件夹&#xff0c;如图所示&#xff1a; 可能是因为权限设置、浏览器限制或 Live Share 的配置问题。以下是逐步排查和解决问题的方法&#xff1a; 1. 确保正确共享了文件夹 在主机&#xff08;Host&a…

.NET 9 运行时中的新增功能

本文介绍了适用于 .NET 9 的 .NET 运行时中的新功能和性能改进。 文章目录 一、支持修剪的功能开关的属性模型二、UnsafeAccessorAttribute 支持泛型参数三、垃圾回收四、控制流实施技术.NET 安装搜索行为性能改进循环优化感应变量加宽Arm64 上的索引后寻址强度降低循环计数器可…

深入解析TK技术下视频音频不同步的成因与解决方案

随着互联网和数字视频技术的飞速发展&#xff0c;音视频同步问题逐渐成为网络视频播放、直播、编辑等过程中不可忽视的技术难题。尤其是在采用TK&#xff08;Transmission Keying&#xff09;技术进行视频传输时&#xff0c;由于其特殊的时序同步要求&#xff0c;音视频不同步现…

MongoDB:数据迁移

业余人员学习 第一种:通过MongoDB命令 参考链接: MongoDB的备份(mongodump)与恢复(mongorestore)_MongoDB_脚本之家 MongoDB数据库管理:全面掌握mongodump和mongorestore的备份与恢复技巧_8055096的技术博客_51CTO博客 1.1、首先进入操作命令行,都不需要进入MongoDB […

网络安全练习之 ctfshow_web

文章目录 VIP题目限免&#xff08;即&#xff1a;信息泄露题&#xff09;源码泄露前台JS绕过协议头信息泄露robots后台泄露phps源码泄露源码压缩包泄露版本控制泄露源码(git)版本控制泄露源码2(svn)vim临时文件泄露cookie泄露域名txt记录泄露敏感信息公布内部技术文档泄露编辑器…

【俄罗斯方块】

【俄罗斯方块】 C语言实现C实现Java实现Python实现 &#x1f490;The Begin&#x1f490;点点关注&#xff0c;收藏不迷路&#x1f490; 首先把经典的俄罗斯方块简化一下&#xff1a;方块有顺序地从屏幕顶端掉下至底部&#xff0c;当碰到障碍物或底部时停下&#xff0c;同时变成…

优化装配,提升品质:虚拟装配在汽车制造中的关键作用

汽车是各种零部件的有机结合体&#xff0c;因此汽车的装配工艺水平和装配质量直接影响着汽车的质量与性能。在汽车装配过程中&#xff0c;经常会发生零部件间干涉或装配顺序不合理等现象&#xff0c;且许多零部件制造阶段产生的质量隐患要等到实际装配阶段才能显现出来&#xf…

【算法】日期问题(C/C++)

目录 日期问题概述 一、闰年判断 问题描述&#xff1a; 解决方法&#xff1a; 代码实现&#xff1a; 二、回文日期 问题描述&#xff1a; 链接&#xff1a;2867. 回文日期 - AcWing题库 解决方法&#xff1a; 代码实现&#xff1a; 三、日期差值 问题描述&#xff1…

FIFO架构专题-异步FIFO及信号

概述 FIFO按时钟可分为&#xff1a;异步FIFO、同步FIFO。 定义 同步FIFO&#xff1a;读时钟和写时钟都相同的FIFO。同步FIFO内部没有异步处理&#xff0c;因此结构简单&#xff0c;资源占用较少。 异步FIFO&#xff1a;读时钟和写时钟可以不同的FIFO。异步FIFO内部有专门的异…

类和对象(上)--类、类的实例化(对象)、this指针

1.类 1.1定位&#xff1a; 和namespace一样&#xff0c;类也有类域。同样起到既保护又限制的功能。别人不能随意访问类里的东西&#xff0c;得通过特定的方式来访问&#xff08;访问方法和命名空间域一样&#xff0c;三种方法&#xff09;。 1.2作用 在C语言中&#xff0c;…

Leetcode 路径总和

使用递归算法 class Solution {public boolean hasPathSum(TreeNode root, int targetSum) {// 如果节点为空&#xff0c;返回falseif (root null) {return false;}// 如果是叶子节点&#xff0c;检查路径和是否等于目标值if (root.left null && root.right null) …

程序里sendStringParametersAsUnicode=true的配置导致sql server cpu使用率高问题处理

一 问题描述 近期生产环境几台sql server从库cpu使用率总是打满&#xff0c;发现抓的带变量值的慢sql&#xff0c;手动代入变量值执行并不慢&#xff0c;秒级返回&#xff0c;不知道问题出在哪里。 二 问题排查 用扩展事件或者sql profiler抓慢sql&#xff0c;抓到了变量值&…

传输层协议TCP

一.TCP协议格式 对于传输层协议我们之前是学过了UDP&#xff0c;对于传输层协议是存在了一定的了解的&#xff0c;所以现在我们再来看TCP协议格式&#xff1a; 我们之前学过UDP的报文格式&#xff0c;所以源端口和目的端口是不需要进行再次讲解的&#xff0c;对于32序号和确认序…