【C++】实现单例模式 [懒汉模式、饿汉模式]

单例模式:保证一个类只被实例化一次!单例模式有懒汉和饿汉两种模式;

懒汉模式:第一次用到类的时候再去实例化;适合在访问量较小的时候使用;

                【时间换空间,懒汉模式本身是线程不安全的!】

饿汉模式:类定义的时候就初始化;由于要进行线程同步,所以在访问量较大或可能访问的线程较多的情况下使用

                 【空间换时间,安全!】

< 饿汉模式 >

template<class T>
class singleton
{
protected:
	sigleton {};  //构造函数
private:
	sigleton(const sigleton&) {}; //禁止拷贝
	sigleton& operator = (const sigleton&) {}; //禁止赋值
	static T* m_instance;
public:
	static T* GetInstance();
};
template<class T>
T* sigleton<T>::GetInstance()
{
	return m_instance;
}
template<class T>
T* sigleton<T>::m_instance = new T();

     在实例化m_instance变量的时候,直接调用类的构造函数,在未使用变量的时候,已经对m_instance进行赋值;在多线程情况下肯定是线程安全的,因为不存在多线程实例化的问题;

<懒汉模式>

template<class T>
class singleton
{
protected:
	sigleton {};  //构造函数
private:
	sigleton(const sigleton&) {}; //禁止拷贝
	sigleton& operator = (const sigleton&) {}; //禁止赋值
	static T* m_instance;
public:
	static T* GetInstance();
};
template<class T>
T* sigleton<T>::GetInstance()
{
	if(m_instance == NULL)
	{
		m_instance = new T();
	}
	return m_instance;
}
template<class T>
T* sigleton<T>::m_instance = NULL;

     在懒汉模式下,定义m_instance变量先等于NULL,调用GetInstance()方法时判断是否要赋值,不安全是因为当多个线程同时调用GetInstance()方法的时候,有可能导致多个实例产生,所以为了实现线程安全,必须加锁

     <改进1> 利用互斥锁来达到线程安全,但影响效率

template<class T>
class singleton
{
protected:
	sigleton {};  //构造函数
private:
	sigleton(const sigleton&) {}; //禁止拷贝
	sigleton& operator = (const sigleton&) {}; //禁止赋值
	static T* m_instance;
public:
	static T* GetInstance();
};
template<class T>
T* sigleton<T>::GetInstance()
{
	pthread_mutex_lock(&mutex);
	if(m_instance == NULL)
	{
		m_instance = new T();
	}
	pthread_mutex_unlock(&mutex);
	return m_instance;
}
template<class T>
                                   //宏来静态初始化互斥锁
pthread_murex_t sigleton<T>::mutex = PTHREAD_MUTEX_INITIALIZER;
template<class T>
T* sigleton<T>::m_instance = NULL;

     每次调用GetInstance()方法进来都要加锁,影响效率!

     <改进2> “双检锁”机制,用局部变量过渡

template<class T>
class singleton
{
protected:
	sigleton {};  //构造函数
private:
	sigleton(const sigleton&) {}; //禁止拷贝
	sigleton& operator = (const sigleton&) {}; //禁止赋值
	static T* m_instance;
public:
	static T* GetInstance();
};
template<class T>
T* sigleton<T>::GetInstance()
{
	if(m_instance == NULL)
	{
		pthread_mutex_lock(&mutex);
		if(m_instance == NULL)
		{
			m_instance = new T();
		}
		pthread_mutex_unlock(&mutex);
	}
	return m_instance;
}
template<class T>
T* sigleton<T>::m_instance = NULL;

      “双检锁”机制,但是当执行m_instance = new T();时,可能类T还没有完成初始化,m_instance就已经有值了,这样会导致另外一个调用GetInstance()方法的线程获取到还未完成初始化的m_instance指针;

     <改进3> 在Linux中还有一种实现方式,Linux提供了一个pthread_once()的函数,函数保证在一个进程中,某个函数只执行一次;

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值