c++之单例模式
1 本篇主要討論下多線程下的單例模式實(shí)現(xiàn):
首先是 double check 實(shí)現(xiàn)方式: 這種模式可以滿足多線程環(huán)境下,只產(chǎn)生一個(gè)實(shí)例。
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_;};? 但是這種實(shí)現(xiàn)存在除bug的隱患, 問題就在: value_ = new T; 上。《程序員的自我修養(yǎng)》上指出:
這樣的代碼是有問題的,問題的來源在于 cpu 的亂序執(zhí)行。c++里的new 包含了兩步。
(1)分配內(nèi)存
(2)調(diào)用構(gòu)造函數(shù)
所以 value_ = new T;? 實(shí)際上包含了三步:
(1)分配內(nèi)存
(2)在分配內(nèi)存的位置上調(diào)用構(gòu)造函數(shù)
(3)將內(nèi)存地址賦值給 value_;
這三步中,(2), (3)兩步是可以顛倒的,也就是說,可能出現(xiàn),先執(zhí)行(3)這是 value_已經(jīng)不為NULL, 當(dāng)出現(xiàn)另一個(gè)對GetInstance的并發(fā)調(diào)用,if 內(nèi)的 value_ != NULL于是返回,但是還沒有調(diào)用構(gòu)造函數(shù)。于是使用這個(gè)指針的時(shí)候,就會(huì)導(dǎo)致崩潰。
這時(shí)候需要保證(2), (3)的執(zhí)行順序,通常需要加上內(nèi)存屏障,保證一定保證(2)執(zhí)行完以后,再執(zhí)行(3)
這里我加上了__sync_synchronize(); 后 實(shí)現(xiàn)是這樣的:
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_;}
?
這樣便可以既保證多線程環(huán)境安全,又保證不會(huì)出現(xiàn)上面的問題。
2. 加上內(nèi)存屏障的示例代碼: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 來實(shí)現(xiàn)單例模式:
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. 水平有限,望及時(shí)指出錯(cuò)誤。謝謝
轉(zhuǎn)載于:https://www.cnblogs.com/newbeeyu/p/6885098.html
與50位技術(shù)專家面對面20年技術(shù)見證,附贈(zèng)技術(shù)全景圖總結(jié)
- 上一篇: python--面向对象--14
- 下一篇: C++ Primer笔记 容器和算法(2