单例模式的实现

1. 单例模式使用的场景

在计算机中,有很多的设备比如说打印机,在打印一份文件时,只需要一个打印机工作,只要有一个打印机就可以完成这个文件的打印工作。相反的,如果系统中有多台打印机同时工作,会造成资源的浪费,也可能打出的文件是不完整的,此时就容易出现问题。

相同的,在一个类中,我们只需要有一个实例来完成它的工作就行了,此时就需要单例模式。

2. 单例模式实现的要求

要实现单例模式完成三个要点(1)只能生成一个实例,(2)这个实例必须由本类实现;(3)这个实例必须自己让系统看见自己;要实现此目的,我们需要做到三个要求:

(1)构造函数是私有的,将构造函数给成private,就不允许创建其他的对象(实例);

(2)类定义中含有一个静态的私有的对象;

(3)提供一个静态的公有的函数来获取这个对象;

3. C++实现单例模式

(1)懒汉式

#include <iostream>
using namespace std;

class CSingleton
{
public:
	static CSingleton* GetInstance()
	{
		if (pInstance == NULL) //判断是否第一次调用
		{
			pInstance = new CSingleton;
		}
		return pInstance;
	}
	void ReleaseInstance()
	{
		delete this;
	}
private:
	CSingleton()
	{}
	CSingleton(const CSingleton& instance);
	~CSingleton()
	{
		pInstance = NULL;
	}
private:
	static CSingleton *pInstance;
};

上面这种方式存在很大的问题,它只能用于单线程,如果是多线程,这个程序就没有任何意义,因为两个线程可能同时执行创建对象函数,这时就相当于创建了两个实例。

(2)我们可以利用加锁实现多线程的单例模式

C++11的锁定义在头文件<mutex>中,包含了四种不同的互斥量。

扫描二维码关注公众号,回复: 60599 查看本文章
  • Mutex: 提供了核心函数 lock() 和 unlock(),以及非阻塞方法的try_lock()方法,一旦互斥量不可用,该方法会立即返回。
  • Recursive_mutex:允许在同一个线程中对一个互斥量的多次请求。
  • Timed_mutex:同上面的mutex类似,但它还有另外两个方法 try_lock_for() 和 try_lock_until(),分别用于在某个时间段里或者某个时刻到达之间获取该互斥量。
  • Recursive_timed_mutex: 结合了timed_mutex 和recuseive_mutex的使用。

我们利用lock()函数和 unlock()函数实现代码:

#include <iostream>
using namespace std;
#include <mutex>

mutex g_lock;
class CSingleton
{
public:
	static CSingleton* GetInstance()
	{
		if (pInstance == NULL)
		{
			g_lock.lock();
			if (pInstance == NULL) //判断是否第一次调用
			{
				pInstance = new CSingleton;
			}
			g_lock.unlock();
			
		}
		return pInstance;
		
	}
	void ReleaseInstance()
	{
		delete this;
	}
private:
	CSingleton()
	{}
	CSingleton(const CSingleton& instance);
	~CSingleton()
	{
		pInstance = NULL;
	}
private:
	static CSingleton *pInstance;
};

在这种方式下,只有pInstance为空时即没有创建时,需要加锁操作,当pInstance创建出来时,就不需要进行加锁操作,因为加锁操作的效率很慢并且耗费资源。这样做不仅可以实现多线程的操作,也提高了效率。


猜你喜欢

转载自blog.csdn.net/qq_37954088/article/details/80070447