Singleton

在软件系统中,经常有这样一些特殊的类,必须保证它们在系统中只存在一个实例,才能确保它们的逻辑正确性、以及良好的效率,比方说:线程池(threadpool)、缓存(cache)、对话框、处理偏好设置和注册表的对象、日志对象,充当打印机、显卡等设备的驱动程序的对象。这些类对象只能有一个实例,如果制造出多个实例,就会导致许多问题产生,例如:程序的行为异常、资源使用过量躲着是不一致的结果。遇到这种情况,我们可以通过单件模式来实现,这个模式保证在任何时刻都只有一个对象。
- 定义: 保证一个类仅有一个实例,并提供一个访问它的全局访问点。
通过维护一个static的成员变量来记录这个唯一的对象实例。
通过提供一个static的接口instance来获得这个唯一的实例。
- 适用性:
(1) 当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。
(2) 当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。
- 代码实现:
(1) 单线程Singleton实现
#ifndef _SINGLETON_H_ #define _SINGLETON_H_ class Singleton { public: static Singleton* Instance(); void OutPut(); private: Singleton(); private: static Singleton* _instance; }; #endif #include "singleton.h" #include "stdio.h" Singleton* Singleton::_instance = NULL; Singleton::Singleton() { printf("Creating unique instance./n"); } Singleton *Singleton::Instance() { if (_instance == NULL) { _instance = new Singleton(); } return _instance; } Void OutPut() { printf("Singleton Pattern./n"); } #include "singleton.h" #include "stdio.h" int main(int argc, char* argv[]) { Singleton *pSgt = Singleton::Instance(); Singleton *pSgt1 = Singleton::Instance(); pSgt->OutPut(); pSgt1->OutPut(); printf("/n"); return 0; }
以上代码在单线程情况下不会出现任何问题。但是在多线程的情况下却不是安全的。如两个线程同时运行到 if (instance == null)判断是否被实例化,一个线程判断为True后,在进行创建instance = new SingleThread_Singleton();之前,另一个线程也判断(instance == null),结果也为True。这样就就违背了Singleton模式的原则(保证一个类仅有一个实例)。
(2) 多线程Singleton实现 引入线程保护代码
#pragma once #include <Windows.h> #include <memory> //线程安全使用的头文件 #ifndef SingletonH #define SingletonH using namespace std; // Base SinglePattern Class class SinglePattern { protected: virtual void InitialInstance() = 0; virtual void DisposeInstance() = 0; }; // Thread Safe Class class CResGuard { public: CResGuard() { m_lGrdCnt = 0; InitializeCriticalSection(&m_cs); } ~CResGuard() { DeleteCriticalSection(&m_cs); } // IsGuarded is used for debugging BOOL IsGuarded() const { return(m_lGrdCnt > 0); } public: class CGuard { public: CGuard(CResGuard& rg) : m_rg(rg) { m_rg.Guard(); }; ~CGuard() { m_rg.Unguard(); } protected: CResGuard& m_rg; }; private: void Guard() { EnterCriticalSection(&m_cs); m_lGrdCnt++; } void Unguard() { m_lGrdCnt--; LeaveCriticalSection(&m_cs); } // Guard/Unguard can only be accessed by the nested CGuard class. friend class CResGuard::CGuard; private: CRITICAL_SECTION m_cs; long m_lGrdCnt; // # of EnterCriticalSection calls }; // Singleton Container template <class T> class Singleton { friend class auto_ptr<T>; protected: static auto_ptr<T> m_Instance; static CResGuard _rs; protected: __fastcall Singleton(){}; virtual ~Singleton(){}; public: static T* __fastcall GetInstance() { CResGuard::CGuard gd(_rs); if(m_Instance.get() == NULL) { m_Instance.reset(new T()); } return m_Instance.get(); } }; template <class T> CResGuard Singleton<T>::_rs; template<class T> auto_ptr<T> Singleton<T>::m_Instance; // MACRO of Singleton Pattern to use #define DECLARE_SINGLETON(type) / friend class auto_ptr<type>; / friend class Singleton<type>; / public: / static type *GetInstance() / { / return Singleton<type>::GetInstance(); / } / protected: / __fastcall type() / { / InitialInstance(); / } / public: / virtual ~type() / { / DisposeInstance(); / } #endif class MySingle : public SinglePattern { DECLARE_SINGLETON(MySingle) protected: virtual void InitialInstance(){} virtual void DisposeInstance(){} public: void Run(){}; }; int main(int argc, char* argv[]) { MySingle::GetInstance()->Run(); return 0; }
本文深入探讨了单例模式的设计理念及其在单线程与多线程环境下的实现方式。介绍了单例模式的基本定义、适用场景及其实现代码,并针对多线程环境下如何保证线程安全进行了详细讲解。
1822

被折叠的 条评论
为什么被折叠?



