分享一个线程安全的单例模板类
单例模式应该说是最简单的设计模式了。在此分享一个线程安全的单例模板类。
template <typename Type> class CSingleton { public: static Type* GetInstance() { // kBeingCreatedMarker用来表示单例实例正在创建过程中。 // 此处初始化为1是因为操作系统不会分配地址为1的指针。 static const volatile intptr_t kBeingCreatedMarker = 1; // 如果m_pInstance不为空且不是正在创建,则返回m_pInstance if (m_pInstance != NULL && m_pInstance != kBeingCreatedMarker) { return reinterpret_cast<Type*>(m_pInstance); } // 使用InterlockedCompareExchange函数保证原子操作 // 函数判断m_pInstance是否等于NULL,如果是则将m_pInstance赋值为kBeingCreatedMarker // 函数返回值为m_pInstance的初始值,通过判断返回值是否等于NULL得知是否可以进行实例化 if (InterlockedCompareExchange( reinterpret_cast<volatile LONG*>(&m_pInstance), static_cast<LONG>(kBeingCreatedMarker), static_cast<LONG>(NULL)) == NULL) { static Type newval; m_pInstance = reinterpret_cast<intptr_t>(&newval); return &newval; } // 如果m_pInstance是kBeingCreatedMarker,即表示正在创建中 // SwitchToThread让出剩余的时间片等待创建过程完成 while (m_pInstance == kBeingCreatedMarker) { SwitchToThread(); } // 到达此处表明创建过程已经完成了 return reinterpret_cast<Type*>(m_pInstance); } Type& operator*() { return *GetInstance(); } Type* operator->() { return GetInstance(); } private: static volatile intptr_t m_pInstance; }; template <typename Type> volatile intptr_t CSingleton<Type>::m_pInstance = NULL;
假设我们有个CCmdManager类
class CCmdManager { public: CCmdManager() { std::cout << "Hello, I am the only one!"; }; };
使用方法很简单,如下:
int main() { CCmdManager *pMgr = CSingleton<CCmdManager>::GetInstance(); CCmdManager &mgr = *(CSingleton<CCmdManager>::GetInstance()); }
如果我们想要完全限制CCmdManager不被实例化第二次,我们可以这么做
class CCmdManager { private: CCmdManager() { std::cout << "Hello, I am the only one!"; }; friend class CSingleton<CCmdManager>; };
通过将构造函数设置为private,且仅对class CSingleton<CCmdManager>开放,就可以保证用户只能使用CCmdManager *pMgr = CSingleton<CCmdManager>::GetInstance()这种方式调用了。
顺便说一下,这个代码的一些局限性
1. 因为使用了InterlockedCompareExchange这个函数,所以只能在Windows下使用,但是不可否定的是这个函数的效率极高,完成比较并交换只要一条指令。
2. CSingleton在实例化对象时,只支持默认构造函数。一般情况下,这个也是可以接受的。