c++之单例模式
1 本篇主要討論下多線程下的單例模式實現:
首先是 double check 實現方式: 這種模式可以滿足多線程環境下,只產生一個實例。
template<typename T>class dclsingleton{public:static T& GetInstance(){if(NULL == value_){MutexGuard mg(mutex_);if (NULL == value_){value_ = new T;}}return *value_;}protected:dclsingleton() { std::cout << "dclsingleton constuctor called" << std::endl; }dclsingleton(const dclsingleton &dcl) {}private:static T* value_;static Mutex mutex_;};? 但是這種實現存在除bug的隱患, 問題就在: value_ = new T; 上。《程序員的自我修養》上指出:
這樣的代碼是有問題的,問題的來源在于 cpu 的亂序執行。c++里的new 包含了兩步。
(1)分配內存
(2)調用構造函數
所以 value_ = new T;? 實際上包含了三步:
(1)分配內存
(2)在分配內存的位置上調用構造函數
(3)將內存地址賦值給 value_;
這三步中,(2), (3)兩步是可以顛倒的,也就是說,可能出現,先執行(3)這是 value_已經不為NULL, 當出現另一個對GetInstance的并發調用,if 內的 value_ != NULL于是返回,但是還沒有調用構造函數。于是使用這個指針的時候,就會導致崩潰。
這時候需要保證(2), (3)的執行順序,通常需要加上內存屏障,保證一定保證(2)執行完以后,再執行(3)
這里我加上了__sync_synchronize(); 后 實現是這樣的:
static T& GetInstance(){if(NULL == value_){MutexGuard mg(mutex_);if (NULL == value_){T* tmp = static_cast<T*>(operator new (sizeof(T)));new (tmp) T();__sync_synchronize();value_ = tmp;}}return *value_;}
?
這樣便可以既保證多線程環境安全,又保證不會出現上面的問題。
2. 加上內存屏障的示例代碼:dcl_single.h
#ifndef __DCL_SINGLE_H #define __DCL_SINGLE_H#include <iostream>namespace yl {class Mutex{public:Mutex(){pthread_mutex_init(&mutex_, NULL);}~Mutex(){pthread_mutex_destroy(&mutex_);}public:void Lock(){pthread_mutex_lock(&mutex_);}void UnLock(){pthread_mutex_unlock(&mutex_);}private:pthread_mutex_t mutex_;};class MutexGuard{public:MutexGuard(Mutex& m) : mutex_(m){mutex_.Lock();}~MutexGuard(){mutex_.UnLock();}private:Mutex mutex_;};template<typename T>class dclsingleton{public:static T& GetInstance(){if(NULL == value_){MutexGuard mg(mutex_);if (NULL == value_){T* tmp = static_cast<T*>(operator new (sizeof(T)));new (tmp) T();__sync_synchronize();value_ = tmp;}}return *value_;}protected:dclsingleton() { std::cout << "dclsingleton constuctor called" << std::endl; }dclsingleton(const dclsingleton &dcl) {}private:static T* value_;static Mutex mutex_;};template<typename T>T* dclsingleton<T>::value_ = NULL;template<typename T>Mutex dclsingleton<T>::mutex_; }#endif View Code
?
singletonTest.cpp
#include "dcl_single.h" #include <iostream>namespace yl {class MgrSg : public dclsingleton<MgrSg>{private:friend class dclsingleton <MgrSg>;MgrSg(){ std::cout << "MgrSg: constructor called" << std::endl; }~MgrSg() { std::cout << "MgrSg: desconstructor called" << std::endl; }public:void print(){std::cout << "print called" << std::endl;}}; }int main(void) {using namespace yl;MgrSg::GetInstance().print();return 0; }?
3. 還可以用 unix 下的 pthread_once 來實現單例模式:
template <typename T>class MySingleton{public:static T & getInstance(){pthread_once(&ponce_, &MySingleton::init);return *instance;}protected:MySingleton() {}MySingleton(const MySingleton&) {}private:static void init(){instance = new T();}private:static pthread_once_t ponce_;static T *instance;};template<typename T>pthread_once_t MySingleton<T>::ponce_ = PTHREAD_ONCE_INIT;template<typename T>T *MySingleton<T>::instance = nullptr; }
?
4.我自己遇到的就是以上兩種情況,若是希望了解更全面,可參考下邊:
http://www.cnblogs.com/liyuan989/p/4264889.html
5. 水平有限,望及時指出錯誤。謝謝
轉載于:https://www.cnblogs.com/newbeeyu/p/6885098.html
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
- 上一篇: python--面向对象--14
- 下一篇: C++ Primer笔记 容器和算法(2