1. 程式人生 > >設計模式 之 單例模式 (C++ 懶漢經典實現 & DCL實現 & 餓漢經典實現)

設計模式 之 單例模式 (C++ 懶漢經典實現 & DCL實現 & 餓漢經典實現)

顧名思義:

單例模式,指的是僅有一個(類)例項。

即:

在應用程式的整個生命週期中,任何時刻,某個類(單例類)僅存在唯一一個例項。

同時僅提供一個全域性訪問點。

單例的實現一般要求滿足:

(1) 類建構函式私有

(2) 提供一個全域性訪問點 一般是靜態的共有方法

一、單例的經典實現

程式碼如下:

class Singleton
{
public:
	// 全域性訪問點
	static Singleton *getInstance()
	{
		if (pInstance == NULL)
		{
			pInstance = new Singleton;
		}

		return pInstance;
	}

private:
	static Singleton *pInstance;	// 唯一例項
	Singleton();
};
單例經典實現的缺陷:

在多執行緒併發的情況下,多個執行緒同時呼叫getInstance()方法,可能會出現pInstance = NULL

這時候會同時建立多個執行緒。

二、單例的多執行緒下實現("雙重鎖")

程式碼如下:

CSingleton.h

#pragma once
#ifndef _CSINGLETON_H_
#define _CSINGLETON_H_
#include <iostream>

struct CCriticalSection
{
public:
	void Lock(){}
	void UnLock(){}
};

// 自己實現的鎖
class Lock
{
public:
	CCriticalSection m_cs;
public:
	// 建構函式
	Lock(CCriticalSection cs):m_cs(cs)
	{
		m_cs.Lock();
	}

	// 解構函式
	~Lock()
	{
		m_cs.UnLock();
	}
};

// 單例類(懶漢模式)
class CSingleton
{
private:
	// 下面這些函式要設為private
	CSingleton();	// 防止出現 new CSingleton()這樣生成例項的方式

	// 禁止拷貝
	CSingleton(const CSingleton&);
	CSingleton& operator=(const CSingleton&);

	// 解構函式也要設定為private
	~CSingleton();

	// 自動析構類(目的是在程式結束時 自動析構掉單例的例項)
	class CGarbo
	{
	public:
		~CGarbo()
		{
			if (CSingleton::m_pInstance != NULL)
			{
				delete CSingleton::m_pInstance;
				m_pInstance = NULL;
			}
		}
	};
public:
	// 臨界區資源(避免多執行緒的訪問衝突)
	//static CCriticalSection m_cs;
	static CSingleton* getInstance();
private:
	// 單例
	static CSingleton* m_pInstance;

	// 自動析構
	static CGarbo m_garbo;
	// 互斥鎖
	static CCriticalSection m_cs;
};

#endif
CSingleton.cpp
#include "CSingleton.h"

CSingleton::CSingleton()
{}

CSingleton::~CSingleton()
{}

CSingleton::CSingleton(const CSingleton& instance)
{}

CSingleton& CSingleton::operator=(const CSingleton& instance)
{
	return *this;
}

// 全域性訪問點 返回單例
CSingleton* CSingleton::getInstance()
{
	if (NULL == m_pInstance)
	{
		Lock lock(m_cs);

		if (NULL == m_pInstance)
		{
			m_pInstance = new CSingleton;
		}
	}

	return m_pInstance;
}

// 懶漢模式

// 靜態變數的例項化
CSingleton* CSingleton::m_pInstance = NULL;
CCriticalSection CSingleton::m_cs;
測試程式碼 main.cpp:
#include <iostream>
#include "CSingleton.h"

using namespace std;

int main(void)
{
	CSingleton *instance1 = CSingleton::getInstance();
	CSingleton *instance2 = CSingleton::getInstance();

	if (instance1 == instance2)
	{
		cout<<"equal instance"<<endl;
	}
	else
	{
		cout<<"different instance"<<endl;
	}

	return 0;
}
【注:上述程式碼均在VS2012環境下編譯執行通過】

大致思想是使用"雙重鎖"思想。

第二個if 塊判斷時 先執行加鎖操作(關鍵區實現) 保證只有一個執行緒可以訪問塊內的語句。

第一個if 塊判斷時 因為只有例項不存在時才需要加鎖操作 例項存在時 我們只需要直接返回例項即可 提高了效率。

注:上述實現的單例都屬於 "懶漢模式"的單例。即:都採取的是用時間換空間的思想。

三、單例的"餓漢模式"

即:無論是否呼叫該類的例項,在程式開始時就會產生一個該類的例項,並在之後程式中僅返回該單例。

注意:

靜態例項初始化保證了執行緒安全。

REASON:靜態例項初始化在程式開始時進入主函式之前就由主執行緒以單執行緒方式完成了初始化。

可以不用考慮多執行緒的問題。

因此這種模式在效能需求較高時,可避免頻繁的鎖競爭。

程式碼如下:

class Singleton
{
private:
	static const Singleton* pInstance;
	Singleton(){}
public:
	static const Singleton* getInstace()
	{
		return pInstance;
	}
};

// 外部初始化(進入主函式之前)
const Singleton* Singleton::pInstance = new Singleton;

-------------------------分割線----------------------

接下來需要考慮資源的釋放 也就是解構函式。

明天起來再寫~~呼呼呼

------------------------03.28 凌晨更新--------------------

增加了析構部分的程式碼

同時封裝為一個單例類

添加了測試程式碼~

歡迎大家指正~~