c++单列模式与线程安全

  通常c++里面的单列模式很容易实现,我们也不需要去考虑其线程安全的问题,但是在多线程环境中我们却必须要考虑到。首先我们来分析下一下的这个单列模式为什么不是线程安全的,通常的单列模式写法:

class MsgOfArrival
{
public:
    ~MsgOfArrival(void);
    MAP_STRING_PNORMALMSGCOLLECTION  m_normalmsgMap;
    static MsgOfArrival* GetInstance();
private:
    MsgOfArrival(void);
    static MsgOfArrival* m_pInstance;
};

MsgOfArrival* MsgOfArrival::m_pInstance = NULL;
MsgOfArrival::MsgOfArrival(void)
{
}

MsgOfArrival::~MsgOfArrival(void)
{
}



  假设两个多线程同时执行GetInstance()函数,那么m_pInstance==NULL时, 两个线程同时进入了if中时就会创建两个指针,这当然是不行的。解决这个问题首先我们会想到加锁,如改成
MsgOfArrival* MsgOfArrival::GetInstance()
{
    if (m_pInstance == NULL)
    {
        EnterCriticalSection(&g_cs);
        m_pInstance = new MsgOfArrival;      LeaveCriticalSection(&g_cs)
    }return m_pInstance;
}

这样当然可以,而且m_pInstance一但new成功,GetInstance调用不会在进入if中,所以大量调用该单列并不会因为临界区造成性能瓶颈。

  第二种方法是静态变量初始化的时候,我们直接让其new一个指针,因为我们知道静态变量是在Main函数还没执行的时候就由主线程完成了初始化,既然单例指针还没进入到main就已经构造了, 那么我们当然不需要在进入main以后的多线程中来担心单例构造的线程安全性。代码如下:

class MsgOfArrival
{
public:
    ~MsgOfArrival(void);
    MAP_STRING_PNORMALMSGCOLLECTION  m_normalmsgMap;
    static const MsgOfArrival* GetInstance();
private:
    MsgOfArrival(void);
    static const MsgOfArrival* m_pInstance;
};

const MsgOfArrival* MsgOfArrival::m_pInstance =  new MsgOfArrival;
MsgOfArrival::MsgOfArrival(void)
{
}

MsgOfArrival::~MsgOfArrival(void)
{
}

const MsgOfArrival* MsgOfArrival::GetInstance()
{
    return m_pInstance;
}

  需要注意m_pInstance使用const进行修饰的,其所指对象是const的也就是说我们不能修改这个单列对象,这也要求我们在调用改单列的函数时该函数也必须是const的如:

int getdata() const;  //函数声明

//函数定义
int  MsgOfArrival::getdata() const
{
    //
    //  return  m_nVal;
}

  当然m_pInstance也可以不用const修饰, 但是这样其其内部数据可以被修改, 这样在多线程的时候是很危险的。

  上面单例模式已经是线程安全的, 但是有个问题, 这个单例被创建后如何释放呢?第一种方法 在在类里面增加一个静态的函数用于释放指针,这样做在程序中我们随时可以释放单例指针。但是有时候我们的单例指针要一直伴随着进程结束,这个时候我们就可以采用第二种方法:

class MsgOfArrival
{
public:
    ~MsgOfArrival(void);
    MAP_STRING_PNORMALMSGCOLLECTION  m_normalmsgMap;
    static const MsgOfArrival* GetInstance();
private:
    class CGarbo
    {
    public:
        ~CGarbo()
        {
            SAFE_DELETE(MsgOfArrival::m_pInstance);
        }
    };
    static CGarbo Garbo;  //清理资源
    MsgOfArrival(void);
    static const MsgOfArrival* m_pInstance;
};

我们在类里面添加了一个CGarbo类,这个类只有一个作用负责清除单列对象指针,定义一个static的Garbo对象, 该对象声明周期与单例对象指针是一样的,这个静态Garbo对象也会在程序结束时释放,这个时候会将单例指针所拥有资源也释放掉。注意SAFE_DELETE是我自己定义的释放宏。

  文章若有不妥,请大家指教。

时间: 2024-10-12 23:11:51

c++单列模式与线程安全的相关文章

设计模式之单列模式

设计模式之单列模式 1,何为单列模式? 即singleton 在某个类采用了单列模式之后  其只能有一个实列对象 ,并且这个实列对象只能有内部自己创建并提供给外部的调用. 2.实现单列模式的方法 分为 :饿汉式 ,懒汉式 下面为饿汉式实现代码: public calss Singleton1{ //将构造函数私有化 防止外部通过new来创建对象 private Singleton1(){ } //创建一个私有静态变量并直接初始化 类加载的时候直接创建对象 private static Singl

设计模式之--单列模式

单例模式就是某个类只存在一个对象(只new 一次),当某个类的初始化比较耗时,耗资源的时候,比如hibernate写在Dao模式中创建session的时候必须写成单例模式,因为你每做一次数据库的操作,都必须创建一个session,这时候用单例模式是最好的,每次都只是同一个实例,sessionFactory 这个是单例的当然了是一个数据库的时候是单例的,整个服务仅使用这么一个工厂就足够了.好多工厂类基本上都是单例的. 单列模式中的两种基本模式 饿汉式.懒汉式.饿汉式是线程安全的,在加载类时创建实例

Java单列模式

设计模式 单列模式的定义和作用 目的:使得类的一个对象成为该类系统中的唯一实列: 定义:一个类有且仅有一个实例,并且自行实列化向整个系统提供?: 单列模式分为 恶汉式  (在创建对象的时候就直接初始化了)以空间换时间:恶汉士线程安全 懒汉式(创建类内的时候先不实列化,在第一次使用的时候在初始化)以时间换空间:懒汉士存在线程风险 单列模式的使用优缺点 原文地址:https://www.cnblogs.com/xiaoruirui/p/10699054.html

单列模式(data与business交互)

public class CommentsBusiness //Business { #region 单列模式 private static CommentBusiness instance; private CommentData dal;//Data private CommentsBusiness() { dal=new CommentData(); } public static CommentBusiness GetInstance() { if(instance==null) ins

PHP面向对象-单列模式

单例模式,在PHP面向对象中应用的比较广泛, 通常为了节省资源,在性能方面上,代码重用性上考虑,使用设计模式是很不错的选择, 比如数据库操作类系统类库等,通常开源代码都会使用单列模式去设计完成,使用单列模式的优点很明显, 可以保证每个类生成实体的唯一性,性能方面有所提高. <?php header("Content-Type:text/html; charset=utf8"); /** * php设计模式 * 三:单列模式 * */ class Sigle{ protected

23种设计模式学习一(单列模式)singleton

单列模式的类 class Singleton { private static Singleton instance; private Singleton() { } public static Singleton Instance { get { if (instance == null) { instance = new Singleton(); } return instance; } } } 通过以下代码,进行测试,是不是同一个实例 Singleton demo = Singleton.

在JAVA和android中常用的单列模式

在很多开发中,项目为了节约资源,都把一个类的构造函数变为私有化,这样整个项目中就不能创建多个实例,这样的方法我们称为单例模式 现在通过代码来简介下这个单例模式: 在新建一个java项目后,创建一个实体类User.java,和测试类,main.java 代码如下: 1 public class User { 2 private static User user; 3 4 //添加该实例的属性 5 private String name; 6 private String sex; 7 privat

线程同步——用户模式下线程同步——Interlocked实现线程同步

1 线程同步分为用户模式下的线程同步和内核对象的线程同步. 2 3 当然用户模式下的线程同步实现速度比内核模式下快,但是功能也有局 4 5 6 7 8 //1.利用原子访问: Interlocked系列函数,关于Interlocked系列函数,我需要知道的是他们,执行的极快 9 10 //(1)首先是InterlockedExchangeAdd兄弟函数, 11 //第一个参数 Addend 代表进行操作数的地址, 12 //第二个参数 Value 代表增加的值,如果是想进行减法,传负数即可 13

JS设计模式——单列模式

核心:保证一个类仅有一个实例,并提供一个访问它的全局访问点 js中的单列模式关键字:创建唯一的对象 (一)基本实现:判断是否已有实例,有则直接返回,否则生成实例 var Single = (function(){ var instance return function(){ if(instance)return instance return instance = this } })() var a = new Single() var b = new Single() console.log