老生常談C++的單例模式與線程安全單例模式(懶漢/餓漢)
1 教科書里的單例模式
我們都很清楚一個簡單的單例模式該怎樣去實現(xiàn):構(gòu)造函數(shù)聲明為private或protect防止被外部函數(shù)實例化,內(nèi)部保存一個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;
}
這是一個很棒的實現(xiàn),簡單易懂。但這是一個完美的實現(xiàn)嗎?不!該方法是線程不安全的,考慮兩個線程同時首次調(diào)用instance方法且同時檢測到p是NULL值,則兩個線程會同時構(gòu)造一個實例給p,這是嚴重的錯誤!同時,這也不是單例的唯一實現(xiàn)!
2 懶漢與餓漢
單例大約有兩種實現(xiàn)方法:懶漢與餓漢。
懶漢:故名思義,不到萬不得已就不會去實例化類,也就是說在第一次用到類實例的時候才會去實例化,所以上邊的經(jīng)典方法被歸為懶漢實現(xiàn);
餓漢:餓了肯定要饑不擇食。所以在單例類定義的時候就進行實例化。
特點與選擇:
由于要進行線程同步,所以在訪問量比較大,或者可能訪問的線程比較多時,采用餓漢實現(xiàn),可以實現(xiàn)更好的性能。這是以空間換時間。
在訪問量較小時,采用懶漢實現(xiàn)。這是以時間換空間。
3 線程安全的懶漢實現(xiàn)
線程不安全,怎么辦呢?最直觀的方法:加鎖。
方法1:加鎖的經(jīng)典懶漢實現(xiàn):
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;
}
方法2:內(nèi)部靜態(tài)變量的懶漢實現(xiàn)
此方法也很容易實現(xiàn),在instance函數(shù)里定義一個靜態(tài)的實例,也可以保證擁有唯一實例,在返回時只需要返回其指針就可以了。推薦這種實現(xiàn)方法,真得非常簡單。
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);
static singleton obj;
pthread_mutex_unlock(&mutex);
return &obj;
}
4 餓漢實現(xiàn)
為什么我不講“線程安全的餓漢實現(xiàn)”?因為餓漢實現(xiàn)本來就是線程安全的,不用加鎖。為啥?自己想!
class singleton
{
protected:
singleton()
{}
private:
static singleton* p;
public:
static singleton* initance();
};
singleton* singleton::p = new singleton;
singleton* singleton::initance()
{
return p;
}
是不是特別簡單呢?
以空間換時間,你說簡單不簡單?
面試的時候,線程安全的單例模式怎么寫?肯定怎么簡單怎么寫呀!餓漢模式反而最懶[正經(jīng)臉]!
以上就是小編為大家?guī)淼睦仙U凜++的單例模式與線程安全單例模式(懶漢/餓漢)全部內(nèi)容了,希望大家多多支持腳本之家~
相關(guān)文章
深入理解memmove()與memcpy()的區(qū)別以及實現(xiàn)方法
本篇文章是對memmove()與memcpy()的區(qū)別以及實現(xiàn)方法進行了詳細的分析介紹,需要的朋友參考下2013-05-05
Visual Studio 2022 Preview 使用 C++20 Module的詳細過程
這篇文章主要介紹了Visual Studio 2022 Preview 使用 C++20 Module的過程,本文通過項目分析實例代碼相結(jié)合給大家介紹的非常詳細,需要的朋友可以參考下2021-09-09
Qt串口通信開發(fā)之Qt串口通信模塊QSerialPort開發(fā)完整實例(串口助手開發(fā))
這篇文章主要介紹了Qt串口通信開發(fā)之Qt串口通信模塊QSerialPort開發(fā)完整實例(串口助手開發(fā)),需要的朋友可以參考下2020-03-03

