C++单例模式与线程安全

C++单例模式

单例模式的主要作用是去除全局变量,这个意义在设计模式或者相关的资料中都有比较详细的介绍。

一、     单例常见实现方式

单例的实现方式比较常见的可以分为两个大类:类静态成员指针,函数静态变量。其中《设计模式》书中主要以类静态成员指针进行了讲解,而在《More effective c++》书中介绍了一种更高效的基于函数静态变量的实现方式,下面简单的对它们进行一下显示和总结。

1.1    类静态成员指针实现示例

为了便于展示,将所有的实现都放到了头文件中,代码如下:

1.        懒惰初始化实现

class CMemberSingleton

{

public:

       ~CMemberSingleton(void){}

       staticCMemberSingleton* GetInstance();

private:

       CMemberSingleton(void){}

       staticCMemberSingleton *m_pInstance;

};

 

CMemberSingleton*CMemberSingleton::m_pInstance = NULL;

 

CMemberSingleton* CMemberSingleton::GetInstance()

{

       if(NULL != m_pInstance)

       {

              m_pInstance= new CMemberSingleton;

       }

       returnm_pInstance;

}

 

2.        普通实现

class CMemberSingleton

{

public:

       ~CMemberSingleton(void){}

       staticCMemberSingleton* GetInstance();

private:

       CMemberSingleton(void){}

       staticCMemberSingleton *m_pInstance;

};

 

CMemberSingleton*CMemberSingleton::m_pInstance = new CMemberSingleton;

 

CMemberSingleton*CMemberSingleton::GetInstance()

{

       returnm_pInstance;

}

 

3.        总结

基于静态成员变量的单例实现,无法实现对于单例的销毁工作,当然直接提供一个DestoryInstance这种函数给使用者调用是可以,但是调用的时机却是很不好把握的。

 

1.2    函数静态变量实现示例

基于函数静态变量来实现单例可以解决1.1中基于类静态成员变量中实例销毁问题。示例代码如下:

class CMemberSingleton

{

       friendCMemberSingleton& GetInstance();

public:

       ~CMemberSingleton(void){}

private:

       CMemberSingleton(void){}

};

 

CMemberSingleton& GetInstance()

{

       staticCMemberSingleton instance;

       returninstance;

}

 

当然根据个人喜好,你也可以将GetInstance写成类的静态函数,实现效果是一致的。

 

1.3    自动销毁的基于类静态成员单例实现

如果说你确实非常喜欢基于静态成员来实现单例,或者某些因素强制你必须使用静态成员,我们也还是可能借助下面的方法来实现自动销毁工作。

class CMemberSingleton

{

public:

       ~CMemberSingleton(void){}

       staticCMemberSingleton* GetInstance();

private:

       CMemberSingleton(void){}

       staticCMemberSingleton *m_pInstance;

       classCGarbo

       {

       public:

              ~CGarbo()

              {

                     if(NULL != CMemberSingleton::m_pInstance)

                     {

                            deleteCMemberSingleton::m_pInstance;

                     }

              }

       };

       staticCGarbo m_garbo;

};

 

CMemberSingleton::CGarboCMemberSingleton::m_garbo = CMemberSingleton::CGarbo();

CMemberSingleton*CMemberSingleton::m_pInstance = NULL;

 

CMemberSingleton*CMemberSingleton::GetInstance()

{

       returnm_pInstance;

}

二、     单例线程安全性

关于单例的实现方式上面已经进行了简单的介绍,如果我们不编写多线程代码,这一段的讨论你可以忽略。

单例是线程安全的吗(注意我们只讨论单例的获取,也就是常见的GetInstance,至于单例对应类的成员函数线程安全性,此处不作讨论)?回答是否定的!单例不是线程安全的,如果你实现的单例被多个线程调用,那么你就要注意了,很可能在某个时间出现异常(通常是程序启动的时候了!)。下面用一个例子展示一下,示例代码如下:

1.        单例代码

classCMemberSingleton

{

public:

       ~CMemberSingleton(void);

       static CMemberSingleton* GetInstance();

private:

       CMemberSingleton(void);

       static CMemberSingleton *m_pInstance;

};

 

CMemberSingleton*CMemberSingleton::m_pInstance = NULL;

 

CMemberSingleton::CMemberSingleton(void)

{

       cout<<"construct CMemberSingleton"<<endl;

}

CMemberSingleton::~CMemberSingleton(void)

{

       cout<<"destoryCMemberSingleton"<<endl;

}

 

CMemberSingleton*CMemberSingleton::GetInstance()

{

       if (NULL == m_pInstance)

       {

              m_pInstance = newCMemberSingleton;

       }

       return m_pInstance;

}

 

2.        主函数代码

void* thread_func(void *param)

{

       CMemberSingleton::GetInstance();

       return NULL;

}

 

int main(char **argv, int argc)

{

       int i = 0;

       pthread_t pids[100] ={0};

       for (i = 0; i < 3;++i)

       {

              pthread_create(&pids[i],NULL, thread_func, NULL);

       }

       for (i = 0; NULL !=pids[i].p; ++i)

       {

              void *p = NULL;

              pthread_join(pids[i],&p);

       }

       system("pause");

       return 0;

}

 

3.        某次的执行结果

图1图1

执行结果可以明显看出,我们需要的是单例,却实际构造了三次,所以单例不一定是线程安全的。

4.        最简单的解决办法

关于解决单例线程安全的办法也许有很多,但是很多情况你都不可避免的要通过线程同步的方式来实现,下面介绍一种不需要线程同步的安全的单例实现。代码如下:

class CMemberSingleton

{

public:

       ~CMemberSingleton(void);

       static CMemberSingleton*GetInstance();

private:

       CMemberSingleton(void);

       static CMemberSingleton*m_pInstance;

};

 

CMemberSingleton* CMemberSingleton::m_pInstance = newCMemberSingleton;

 

CMemberSingleton::CMemberSingleton(void)

{

       cout<<"constructCMemberSingleton"<<endl;

}

CMemberSingleton::~CMemberSingleton(void)

{

       cout<<"destoryCMemberSingleton"<<endl;

}

 

CMemberSingleton* CMemberSingleton::GetInstance()

{

       return m_pInstance;

}

关于运行的结果就不再上图了,原理大家也应该明白,类的静态成员会在main函数运行之间就进行初始化的操作,如果我们不把它初始化为NULL,而是直接初始化一个对象给它,那么在有线程访问时,它已经初始化完成了,所以不会有线程同步的问题了。

虽然这个办法很好的解决了多线程安全问题,但是关于单例对象的销毁工作,就需要额外的实现了,你喜欢提供DestoryInstance这种函数,还是采用1.3中的“垃圾工”来帮你完成销毁任务呢?

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值