当前位置: 首页 > wzjs >正文

南京 网站建设seo店铺描述

南京 网站建设,seo店铺描述,安徽建设信息网站,织梦网站案例文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全(Thread Safety) 线程安全是指在多线程环境下,某个函数、类或代码片段能够被多个线程同时调用时,仍能保证数据的一致性和逻辑的正确性&#xf…

文章目录

  • 1. 基本概念
  • 2. 设计要点
  • 3. 实现方式
  • 4. 详解懒汉模式

1. 基本概念

线程安全(Thread Safety)

线程安全是指在多线程环境下,某个函数、类或代码片段能够被多个线程同时调用时,仍能保证数据的一致性和逻辑的正确性,不会因线程切换导致错误结果。

单例模式(Singleton Pattern)

单例设计模式是一种创建型设计模式,其核心目的是确保一个类只有一个实例存在,并提供全局访问点来获取该实例。它常用于管理全局资源(如配置信息、日志系统、数据库连接池等),避免重复创建和资源竞争。

2. 设计要点

  1. 构造函数和析构函数是私有的,不允许外部生成和释放
    • 禁止外部实例化:外部代码无法通过 new 或直接声明的方式创建对象,确保唯一实例的控制权在类自身。
    • 控制生命周期:析构函数私有化可防止外部意外删除单例对象,保证其生命周期与程序一致。
    • 符合单一职责原则:类的创建和销毁逻辑由自身管理,避免外部干扰。
  2. 静态成员变量和静态返回单例的成员函数
    • 全局访问点:通过静态方法 getInstance() 提供统一的实例获取方式,替代直接访问全局变量。
    • 延迟初始化(懒汉式):仅在首次调用时创建实例,节省资源。
    • 线程安全(需额外处理):可通过锁或局部静态变量(C++11 后)确保多线程安全。
      • 在单例模式中,如果多个线程同时调用 getInstance() 方法,可能导致多次创建实例(如懒汉模式未加锁时),破坏单例的唯一性。
      • 解决方案
        • 加锁(互斥量):在 getInstance() 中使用互斥锁(如 std::mutex)确保线程同步。
        • 局部静态变量(C++11):利用编译器保证局部静态变量的初始化是线程安全的。
        • 饿汉模式:提前初始化实例,避免多线程竞争。
  3. 禁用拷贝构造函数和赋值运算符
    • 防止拷贝:避免通过拷贝构造函数复制单例对象,破坏唯一性。
    • 防止赋值:禁止通过赋值运算符覆盖单例对象,如 instance2 = instance1
    • 强制单例约束:从语法层面杜绝意外破坏单例模式的行为。
要点解决的问题实际意义
私有构造/析构外部随意创建或销毁实例确保实例的唯一性和可控性
静态成员与访问方法全局访问与资源管理提供统一入口,支持延迟初始化与线程安全
禁用拷贝与赋值意外复制导致多实例维护单例的严格唯一性

3. 实现方式

懒汉模式

懒汉模式的核心是延迟初始化(Lazy Initialization),即在首次调用 getInstance() 时才创建单例实例。在此之前,实例未被分配内存。

特点

  • 优点
    • 节省资源:若单例对象未被使用,则不会创建。
    • 适合初始化耗时的对象(如文件系统、网络连接)。
  • 缺点
    • 需处理线程安全问题(多线程下可能重复创建)。
    • 首次访问可能因初始化导致延迟。

饿汉模式

饿汉模式的核心是提前初始化,即在程序启动时(或类加载时)直接创建单例实例,无论是否被使用。

特点

  • 优点
    • 线程安全:实例在程序启动时初始化,避免多线程竞争。
    • 代码简单:无需处理复杂的线程同步逻辑。
  • 缺点
    • 可能浪费资源:即使未使用单例对象,也会占用内存。
    • 初始化时间可能影响程序启动速度。

实现样例

class Singleton {
public:static Singleton* getInstance() {return &instance; // 直接返回已初始化的实例}
private:static Singleton instance;Singleton() {}~Singleton() {}
};
// 程序启动时初始化(饿汉模式)
Singleton Singleton::instance;

对比懒汉模式与饿汉模式

特性懒汉模式饿汉模式
初始化时机首次调用 getInstance()程序启动时(或类加载时)
线程安全需额外处理(如加锁或 C++11 特性)天然线程安全
资源占用按需分配,节省资源提前占用内存,可能浪费资源
适用场景初始化耗时、使用频率不确定的对象初始化简单、使用频繁的对象

实际开发中,推荐使用 C++11 的局部静态变量懒汉模式(Meyers’ Singleton,线程安全且代码简洁),或根据场景选择饿汉模式。

4. 详解懒汉模式

参考:【C++面试题】手撕单例模式_哔哩哔哩_bilibili

样例1

class Singleton1 {
public:// 要点2static Singleton1 * GetInstance() {if(_instance == nullptr) {_instance = new Singleton1();}return _instance;}
private:// 要点1Singleton1() {}~Singleton1() {std::cout << "~Singleton1()\n";}// 要点3Singleton1(const Singleton1 &) = delete;Singleton1& operator = (const Singleton1&) = delete;Singleton1(Singleton1 &&) = delete;Singleton1& operator = (Singleton1 &&) = delete;// 要点2static Singleton1 *_instance; 
};
Singleton1* Singleton1::_instance = nullptr;

存在错误:

  • 该类创建的单例对象在堆中,虽然资源会被释放,但其在释放的时候是无法调用析构函数的。
  • 非线程安全

样例2

class Singleton2 {
public:static Singleton2 * GetInstance() {if(_instance == nullpte) {_instance = new Singleton2();atexit(Destructor);}return _instance;}
private:static void Destructor() {if(nullptr != _instance) {delete _instance;_instance = nullptr;}}Singleton2() {}~Singleton2() {std::cout << "~Singleton2()\n";}Singleton2(const Singleton2 &) = delete;Singleton2& operator = (const Singleton2&) = delete;Singleton2(Singleton2 &&) = delete;Singleton2& operator = (Singleton2 &&) = delete;static Singleton2 *_instance; 
};
Singleton2* Singleton2::_instance = nullptr;

针对样例1的问题,添加atexit(),在程序结束时手动释放对象,从而调用析构函数

存在问题:

  • 非线程安全

样例3

class Singleton3 {
public:static Singleton3 * GetInstance() {std::lock_guard<std::mutex> lock(_mutex);if(_instance == nullptr) {std::lock_guard<std::mutex> lock(_mutex);if(_instance == nullptr) {_instance = new Singleton3();// 1. 分配内存// 2. 调用构造函数// 3. 返回对象指针 atexit(Destructor);}}return _instance;}
private:static void Destructor() {if(nullptr != _instance) {delete _instance;_instance = nullptr;}}Singleton3() {}~Singleton3() {std::cout << "~Singleton3()\n";}Singleton3(const Singleton3 &) = delete;Singleton3& operator = (const Singleton3&) = delete;Singleton3(Singleton3 &&) = delete;Singleton3& operator = (Singleton3 &&) = delete;static Singleton3 *_instance; static std::mutex _mutex;
};
Singleton3* Singleton3::_instance = nullptr;
std::mutex Singleton3::_mutex;

在创建实例对象是使用互斥锁来实现线程安全

  • 单检测

    先加锁,再判断是否需要创建对象;

    该方法只需要检测一次,但是在已经创建对象的情况下,只需要检测然后返回就行,不需要再第一次检测前加锁(力度过大,效率低)

  • 双检测(Double-Checked Locking,DCL)

    先做第一次检测,然后在需要创建对象时才加锁,此时多线程程序会出现多个线程同时通过一次检测到创建对象的代码块,所以需要第二次检测对象是否创建来避免重复创建

存在问题

在多线程程序中,CPU会进行指令重排,如new操作的正常顺序应该是(1-2-3),在指令重排之后执行顺会变为(1-3-2)。此时如果某个线程执行到new的“返回对象指针操作”,而另外一个线程执行到第一次检测,则会出现另外一个线程返回为初始化对象的情况。


样例4:(面试八股的重点

class Singleton4 {
public:static Singleton4 * GetInstance() {Singleton4* tmp = _instance.load(std::memory_order_relaxed);std::atomic_thread_fence(std::memory_order_acquire);if(tmp == nullptr) {std::lock_guard<std::mutex> lock(_mutex);tmp = _instance.load(std::memory_order_relaxed);if(tmp == nullptr) {tmp = new Singleton4();std::atomic_thread_fence(std::memory_order_release);_instance.store(tmp, std::memory_order_relaxed);atexit(Destructor);}}return tmp;}
private:static void Destructor() {Singleton4* tmp = _instance.load(std::memory_order_relaxed);if(nullptr != tmp) {delete tmp;}}Singleton4() {}~Singleton4() {std::cout << "~Singleton4()\n";}Singleton4(const Singleton4 &) = delete;Singleton4& operator = (const Singleton4&) = delete;Singleton4(Singleton4 &&) = delete;Singleton4& operator = (Singleton4 &&) = delete;static std::atomic<Singleton4*> _instance;static std::mutex _mutex;
};
std::atomic<Singleton4*> Singleton4::_instance;
std::mutex Singleton4::_mutex;

使用内存屏障和原子操作来解决指令重排的问题

内存屏障

  • 作用
    强制限制指令重排,并确保内存操作的可见性(即一个线程的写入对其他线程立即可见)。
  • 类型
    • 获取屏障(acquire fence)
      后续读/写操作不会重排到屏障前,且能读取其他线程的释放操作结果。
    • 释放屏障(release fence)
      前面的读/写操作不会重排到屏障后,且保证当前线程的写入对其他线程可见。
  • 代码中的应用
    • 获取屏障:确保 if(tmp == nullptr) 之后的代码能看到其他线程的完整初始化结果。
    • 释放屏障:确保 new 的构造操作完成后,再存储指针到 _instance

原子操作

  • 定义
    不可分割的操作,保证对变量的读写要么完全执行,要么不执行,不会出现中间状态。
  • 内存顺序(Memory Order)
    • memory_order_relaxed:仅保证原子性,无同步或顺序约束(允许指令重排)。
    • memory_order_acquire/release:与屏障配合,实现同步语义。
  • 代码中的应用
    _instance 被声明为 std::atomic<Singleton4*>,确保其读写是原子的,避免数据竞争。

原子操作详情参考:C++八股 —— 原子操作-CSDN博客


样例5

class Singleton5 {
public:static Singleton5* GetInstance() {static Singleton5 instance;return &instance;}
private:Singleton5() {}~Singleton5() {std::cout << "~Singleton5()\n";}Singleton5(const Singleton5 &) = delete;Singleton5& operator = (const Singleton5&) = delete;Singleton5(Singleton5 &&) = delete;Singleton5& operator = (Singleton5 &&) = delete;
};

静态局部变量具备单例的全部三个特性

最简单也是最推荐的版本


样例6

template<typename T>
class Singleton {
public:static T* GetInstance() {static T instance;return &instance;}
protected:Singleton() {}virtual ~Singleton() {std::cout << "~Singleton()\n";}
private:Singleton(const Singleton &) = delete;Singleton& operator = (const Singleton&) = delete;Singleton(Singleton &&) = delete;Singleton& operator = (Singleton &&) = delete;
};class DesignPattern : public Singleton<DesignPattern> {friend class Singleton<DesignPattern>;
private:DesignPattern() {}~DesignPattern() {std::cout << "~DesignPattern()\n";}
};

类模板封装单例的三个特性,使用时直接继承即可。

  • 基类构造和析构函数设置为protected是因为需要其对子类时可见的
  • 友元是为了让基类能访问子类的构造析构函数
http://www.dtcms.com/wzjs/327907.html

相关文章:

  • 深圳招聘网站大全搜索大全引擎
  • 建设网站是什么自助建站申请
  • 天津网站app建设关联词有哪些关系
  • 深圳网站建制作seo标题优化的方法
  • 哈尔滨cms建站网络网站推广选择乐云seo
  • 怎么做网站代购网络营销师官网
  • 专用主机网站建设seo怎么去优化
  • 江津网站建设怎么样武汉seo技术
  • 湖北省建设网站搜索引擎优化时营销关键词
  • 网页设计尺寸px是什么意思上海网站快速排名优化
  • 建站技巧企业查询免费
  • WordPress打开文章页面404白山seo
  • 网站维护和推广农产品推广方案
  • 南山网站公司定中央新闻直播今天
  • ppt的免费网站搜索网站关键词
  • 临邑网站制作自己搭建一个网站
  • 怎么在网站中做视频背景天津seo优化公司
  • 江门免费网站建站模板百度云链接
  • 有源码如何搭建网站百度推广优化中心
  • 请人做网站收费百度推广开户费用多少
  • 织梦网站设计四川seo关键词工具
  • 免费帮朋友做网站网站首页面设计
  • 北京高端网站建设服务下拉框关键词软件
  • 浙江网站建设服务网络推广预算方案
  • 大型网页设计公司深圳博惠seo
  • 河南省建设厅职称网站徐州自动seo
  • 微信公众平台视频网站开发想做网站找什么公司
  • 临沂网站建设哪家公司好全国最新实时大数据
  • 厦门网站建设公司排行榜百度推广投诉热线
  • 礼品兑换网站怎么做百度高级检索入口