設計模式之單例模式
@(設計模式)[設計模式, C++實現]
簡單的單例模式(非線程安全)
一個很容易想到的單例模式的實現:
構造函數聲明爲private或protected,防止外部函數將其實例化,內部保存一個private static類指針保存唯一的實例,再由一個public函數返回該實例。
class singleton
{
protected:
singleton(){}
private:
static singleton* p;
public:
static singleton* instance();
};
singleton* singleton::p = NULL;
singleton* singleton::instance()
{
if (p == NULL)
p = new singleton();
return p;
}
該實現簡單易懂,但是並不是線程安全的單例模式,因爲假如兩個線程同時調用instance()函數,同時發現p==NULL,並同時構造一個新的實例並賦值給p,這樣不僅實現了兩個實例,還讓兩個線程獲得了不同的實例,顯然是錯誤的。
懶漢的單例模式(線程安全)
懶漢的單例模式:不到迫不得已就不去實例化類,也就是第一次調用的時候纔會實例化類(上面的實現也是懶漢單例模式)。
想實現線程安全的單例模式由兩種辦法:1.加鎖,2.使用內部靜態變量
加鎖的懶漢實現
也就是對p加鎖,防止同時訪問。
class singleton
{
protected:
singleton()
{
pthread_mutex_init(&mutex);
}
private:
static singleton* p;
public:
static pthread_mutex_t mutex;
static singleton* initance();
};
pthread_mutex_t singleton::mutex;
singleton* singleton::p = NULL;
singleton* singleton::initance()
{
if (p == NULL)
{
pthread_mutex_lock(&mutex);
if (p == NULL)
p = new singleton();
pthread_mutex_unlock(&mutex);
}
return p;
}
內部靜態變量的懶漢實現
在instance函數裏定義一個靜態的實例,也可以保證擁有唯一實例,在返回時只需要返回其指針就可以了。值得注意的是,在C++0X之前,編譯器並沒有保證內部靜態變量的線程安全,所以也需要加鎖,但在C++0X之後就不用了。
class singleton
{
protected:
singleton()
{
pthread_mutex_init(&mutex);
}
public:
static pthread_mutex_t mutex;
static singleton* initance();
int a;
};
pthread_mutex_t singleton::mutex;
singleton* singleton::initance()
{
pthread_mutex_lock(&mutex);//before C++0X
static singleton obj;
pthread_mutex_unlock(&mutex);//before C++0X
return &obj;
}
餓漢的單例模式
由靜態初始化實例保證其線程安全性:
靜態實例初始化在程序開始時進入主函數之前就由主線程以單線程方式完成了初始化,不必擔心多線程問題。
故在性能需求較高時,應使用這種模式,避免頻繁的鎖爭奪。
class singleton
{
protected:
singleton(){}
private:
static singleton* p;
public:
static singleton* initance();
};
singleton* singleton::p = new singleton;
singleton* singleton::initance()
{
return p;
}