前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >c 线程安全的单例模式-C++单例模式(线程安全、内存释放)

c 线程安全的单例模式-C++单例模式(线程安全、内存释放)

作者头像
囍楽云
发布2022-12-29 13:45:20
1.8K0
发布2022-12-29 13:45:20
举报
文章被收录于专栏:囍楽云博客

  一、懒汉模式:即第一次调用该类实例的时候才产生一个新的该类实例,并在以后仅返回此实例。

  需要用锁,来保证其线程安全性:原因:多个线程可能进入判断是否已经存在实例的if语句,从而non thread safety.

  使用double-check来保证thread safety.但是如果处理大量数据时,该锁才成为严重的性能瓶颈。

  1、静态成员实例的懒汉模式:

代码语言:javascript
复制
`class Singleton  
{  
private:
static Singleton* m_instance;  
Singleton(){}  
public:

static Singleton* getInstance();  
};  
Singleton* Singleton::getInstance()  
{  
   if(NULL == m_instance)  
   {

   Lock();//借用其它类来实现,如boost  
   if(NULL == m_instance)  
   {  
       m_instance = new Singleton;  
   }  
   UnLock();  
}  
   return m_instance;  
} `

  2、内部静态实例的懒汉模式

  这里需要注意的是c 线程安全的单例模式,C++0X以后,要求编译器保证内部静态变量的线程安全性,可以不加锁。但C++ 0X以前,仍需要加锁。

代码语言:javascript
复制
`class SingletonInside  
{  
private:
SingletonInside(){}  
public:

static SingletonInside* getInstance()  
{  
    Lock(); // not needed after C++0x  
    static SingletonInside instance;  
    UnLock(); // not needed after C++0x  
    return instance;   
}  
};  `

  二、饿汉模式:即无论是否调用该类的实例,在程序开始时就会产生一个该类的实例,并在以后仅返回此实例。

  由静态初始化实例保证其线程安全性,WHY?因为静态实例初始化在程序开始时进入主函数之前就由主线程以单线程方式完成了初始化,不必担心多线程问题。

  故在性能需求较高时,应使用这种模式,避免频繁的锁争夺。

代码语言:javascript
复制
`class SingletonStatic  
{  
private:
static const SingletonStatic* m_instance;  
SingletonStatic(){}  
public:

static SingletonStatic* getInstance()  
{  
    return m_instance;  
}  
};  
//外部初始化 before invoke main  

  指向的空间什么时候释放呢?更严重的问题是,该实例的析构函数什么时候执行?

  如果在类的析构行为中有必须的操作,比如关闭文件,释放外部资源,那么上面的代码无法实现这个要求。我们需要一种方法,正常的删除该实例。

  可以在程序结束时调用()c 线程安全的单例模式,并对返回的指针掉用delete操作。这样做可以实现功能,但不仅很丑陋,而且容易出错。因为这样的附加代码很容易被忘记,而且也很难保证在delete之后,没有代码再调用函数。

  一个妥善的方法是让这个类自己知道在合适的时候把自己删除,或者说把删除自己的操作挂在操作系统中的某个合适的点上,使其在恰当的时候被自动执行。

  我们知道,程序在结束的时候,系统会自动析构所有的全局变量。事实上,系统也会析构所有的类的静态成员变量,就像这些静态成员也是全局变量一样。利用这个特征,我们可以在单例类中定义一个这样的静态成员变量,而它的唯一工作就是在析构函数中删除单例类的实例。如下面的代码中的CGarbo类(Garbo意为垃圾工人):

代码语言:javascript
复制
`class CSingleton  
{  
//其他成员  
public:
static CSingleton* GetInstance();  
private:

CSingleton(){};  
static CSingleton * m_pInstance;  
class CGarbo //它的唯一工作就是在析构函数中删除CSingleton的实例  
{  
public:  
    ~CGarbo()  
    {  
        if( CSingleton::m_pInstance )  
            delete CSingleton::m_pInstance;  
    }  
}

Static CGabor Garbo; //定义一个静态成员,程序结束时,系统会自动调用它的析构函数  
};  `

  类CGarbo被定义为的私有内嵌类,以防该类被在其他地方滥用。

  程序运行结束时,系统会调用的静态成员Garbo的析构函数,该析构函数会删除单例的唯一实例。

  使用这种方法释放单例对象有以下特征:

  在单例类内部定义专有的嵌套类;

  在单例类内定义私有的专门用于释放的静态成员;

  利用程序在结束时析构全局变量的特性,选择最终的释放时机;

  使用单例的代码不需要任何操作,不必关心对象的释放。

  具体代码如下:

代码语言:javascript
复制
#include >   
using namespace std;  
class Singleton   
{   
public:  
    static Singleton *GetInstance();  
private:  
    Singleton()  
    {  
        cout 
[1]: https://xuan.ddwoo.top/index.php/archives/560/
[2]: https://xuan.ddwoo.top/index.php/archives/565/
[3]: https://xuan.ddwoo.top/index.php/archives/556/
[4]: https://xuan.ddwoo.top/index.php/archives/560/                
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档