ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

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

2019-09-06 15:38:06  阅读:186  来源: 互联网

标签:const template GetInstance sigleton 模式 instance mutex 单例 饿汉


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

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

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

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

                 【空间换时间,安全!】

< 饿汉模式 >

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()的函数,函数保证在一个进程中,某个函数只执行一次;

标签:const,template,GetInstance,sigleton,模式,instance,mutex,单例,饿汉
来源: https://blog.csdn.net/weixin_40740059/article/details/100578589

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有