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

来源:互联网 发布:苹果手机用4g网络很卡 编辑:程序博客网 时间:2024/06/03 21:39

废话不多说,常用的代码积淀下来。

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

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

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

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

复制代码
 1 class Singleton 2 { 3 private: 4     static Singleton* m_instance; 5     Singleton(){} 6 public: 7     static Singleton* getInstance(); 8 }; 9 10 Singleton* Singleton::getInstance()11 {12     if(NULL == m_instance)13     {14         Lock();//借用其它类来实现,如boost15         if(NULL == m_instance)16         {17             m_instance = new Singleton;18         }19         UnLock();20     }21     return m_instance;22 }
复制代码

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

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

复制代码
 1 class SingletonInside 2 { 3 private: 4     SingletonInside(){} 5 public: 6     static SingletonInside* getInstance() 7     { 8         Lock(); // not needed after C++0x 9         static SingletonInside instance;10         UnLock(); // not needed after C++0x11         return instance; 12     }13 };
复制代码

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

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

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

复制代码
 1 class SingletonStatic 2 { 3 private: 4     static const SingletonStatic* m_instance; 5     SingletonStatic(){} 6 public: 7     static const SingletonStatic* getInstance() 8     { 9         return m_instance;10     }11 };12 13 //外部初始化 before invoke main14 const SingletonStatic* SingletonStatic::m_instance = new SingletonStatic;
复制代码

(完)

  
#1楼 2012-12-21 16:05 xjb_221  
不错
支持(0)反对(0)
  
#2楼 2013-11-20 20:59 果冻想  
谢谢楼主的分享;看了楼主的文章,让小弟地壶灌顶啊。才知道自己的渺小。

对于楼主的这篇文章,由于小弟学艺不精,有几个地方看不懂~希望能得到楼主的指教。提前谢过了。

在“二、饿汉模式”中,SingletonStatic类的构造函数已经是private的了,怎么还可以在外部进行new实例化操作,楼主的代码,小弟已经运行过了,确实没有错误,但是小弟着实不懂,希望得到你的解答。谢谢。
支持(0)反对(0)
  
#3楼 2013-11-29 15:31 Moondark  
@ 宁采臣
路过,楼主的文章的确不错,对于你的问题,可以这样解答:private是类外不能访问的,但你看上述,它是通过类内元素m_instance进行new操作的,所以能够成功。

对于为何这里要采用const static,表示不是很理解
支持(0)反对(0)
  
#4楼[楼主2013-12-04 11:47 Jone Zhang  
@ 宁采臣
因为这个new实例化不是new对象,而是初始化(initialization),C++标准规定,非整型和枚举型静态常量类成员需要在类外进行初始化,就是说假如你写成:
private:
static const SingletonStatic* m_instance = new SingletonStatic;
编译是不成功的,因为这类声明只是个“声明式”(declaration)
,而不是“定义式”(definition),你尝试在类声明中进行初始化的话,编译不知道把这个对象初始化到哪去。
但是假如你的静态常量类成员是整型或枚举型的,却可以这样做,如:
private:
static const int someInt = 2;
为什么整型或枚举型可以,这是编译器层面的东西了,可以简单理解为因为这个静态常量类成员是一个整数,可以直接表示为机器数(当然是常量)。
这么说希望你能明白。
支持(1)反对(0)
  
#5楼[楼主2013-12-04 11:53 Jone Zhang  
@ Moondark
const和static都是必须的

const是保证这个单例对象不会被修改,
static是保证这个单例对象在程序开始时进入主函数之前就被初始化了,而且是线程安全的。

都是出于安全性的需求
支持(0)反对(0)
  
#6楼 2014-02-24 15:58 eksay  
const SingletonStatic* SingletonStatic::m_instance = new SingletonStatic;

作为初始化的理解很受用,好文章。
支持(0)反对(0)
  
#7楼 2014-03-12 11:43 stupidguy  
3 private:
static const SingletonStatic* m_instance;
5 SingletonStatic(){}
6 public:
static SingletonStatic* getInstance()
8 {
9 return m_instance;
10 }


将一个常量变成变量返回,你不觉得会编译不过吗?

0 0