單例模式,一般我喜歡這樣實現
class singletest
;singletest *singletest::instance()
singletest::singletest()
singletest::~singletest()
然後這樣用
singletest *ts =singletest::instance();
這麼實現的乙個好處就是比較簡單,而且不會有記憶體洩露。但如果在多執行緒環境下是否安全呢?多執行緒環境下可能會有兩種情況:
第一,如果兩個執行緒同時呼叫singletest *ts = singletest::instance();,如果執行緒一先執行構造,但還沒構造完,執行緒二構造的時候發現還沒有構造例項,會再次執行構造,單例就變成了兩例。
第二,如果兩個執行緒都要對成員變數進行讀寫,那麼會不會發生競爭呢?
理論分析一下:
第一種情況,c++11標準的編譯器是執行緒安全的,c++11標準要求編譯器保證static的執行緒安全。而c++11之前標準的編譯器則是不確定,關鍵看編譯器的實現。
第二種情況,任何標準下都不是執行緒安全的。
第一種情況,因為有標準的硬性規定,倒是不需要測試了。那麼第二種情況什麼樣?寫個**測試一下
#include
#include
#include
class singletest
;singletest *singletest::instance()
void singletest::test()
}int singletest::get()
singletest::singletest()
singletest::~singletest()
void *threadfunc(void *arg)
int main(int argc, char* argv)
singletest::test()函式執行了5000次累加,兩個執行緒同時呼叫該函式,如果是執行緒安全的,最後的結果應該是10000,如果執行緒是不安全的,最後的結果應該不確定。
經過測試,最後的結果也確實是不確定的,說明的確是執行緒不安全。
既然執行緒不安全,那麼加個鎖會是什麼樣?**加個鎖,再試一下。
class singletest
;singletest *singletest::instance()
void singletest::test()
}int singletest::get()
singletest::singletest()
singletest::~singletest()
經過測試,這樣就執行緒安全了。
但新的問題又來了,如果有多個成員變數,是乙個變數加乙個鎖?還是用同乙個鎖?
如果用同乙個鎖,那麼每次對成員變數進行讀寫的時候都要上鎖。乙個執行緒需要訪問成員變數a,先上鎖,另乙個執行緒要訪問b,此時a和b是沒有發生競爭的,但由於用了同乙個鎖,那麼b也要等著a將鎖釋放後才能進行操作。
如果乙個變數用乙個鎖,倒是不會發生之前的那種無必要的資源浪費,但鎖多了難免麻煩也就多了。
這就是乙個取捨問題了。
還有一種方案,把鎖放在類的外面,由執行緒函式去處理鎖
static pthread_mutex_t mutex = pthread_mutex_initializer;
class singletest
;singletest *singletest::instance()
void singletest::test()
}int singletest::get()
singletest::singletest()
singletest::~singletest()
void *threadfunc(void *arg)
這樣也是執行緒安全的,但也有乙個問題,類的外面並不知道究竟哪個成員函式需要上鎖,為了安全,每次呼叫成員函式都要上鎖,還是會存在資源浪費的情況。
看來,這種單例的實現方式也與不爽的地方,而且,如果是c++11之前的編譯器,構造的執行緒安全性也是不確定的。
如果是c++11之前的編譯器,可以這樣實現
class singletest
;singletest singletest::st;
singletest *singletest::instance()
void singletest::test()
}int singletest::get()
singletest::singletest()
singletest::~singletest()
這種方法有個缺陷,就是如果構造的時候需要傳入引數,這種方法就不行了,而且也存在成員變數鎖的問題。
再試試下面這種實現
class singletest}};
int m;
static singletest* m_instance;
pthread_mutex_t m_mutex;
static pthread_mutex_t m_insmutex;
static cgarbo garbo;
};pthread_mutex_t singletest::m_insmutex = pthread_mutex_initializer;
singletest* singletest::m_instance = null;
singletest::cgarbo singletest::garbo;
singletest *singletest::instance()
s = pthread_mutex_unlock(&m_insmutex);
if (s != 0)
printf("unlock error\n");
}return m_instance;
}void singletest::test()
}int singletest::get()
singletest::singletest()
singletest::~singletest()
這種實現任何標準下都是構造執行緒安全的,也不會有記憶體洩露,同時也支援構造時輸入,但實現起來太麻煩,單單構造都需要乙個鎖。
但成員變數鎖的問題還是存在的,一直沒有找到比較完美的方法。
手寫乙個執行緒安全的單例工廠模式
簡單介紹一下倆個模式 單例模式 乙個類只會被產生乙個靜態的物件。工廠模式 構造方法不對外提供。提供乙個方法,包括產生物件和對物件的初始化。同時保證多執行緒獲取物件時,獲取的是同乙個物件。public class resource public resource newinstance return ...
執行緒安全的單例模式
廢話不多說,常用的 積澱下來。一 懶漢模式 即第一次呼叫該類例項的時候才產生乙個新的該類例項,並在以後僅返回此例項。需要用鎖,來保證其執行緒安全性 原因 多個執行緒可能進入判斷是否已經存在例項的if語句,從而non thread safety.使用double check來保證thread safe...
執行緒安全的單例模式
單例模式是為了保證乙個類只有乙個例項而且易於外界訪問。所以一般只有把建構函式,拷貝函式,析構函式,賦值函式,變數名變為私有。再用乙個get函式訪問提供介面即可。考慮執行緒安全就要加鎖。一 懶漢模式 1 靜態成員例項的懶漢模式 class singleton public static singlet...