C 實現執行緒安全單例類

2021-08-04 21:09:38 字數 2630 閱讀 4370

單例模式是一種非常常用的設計模式,幾乎在稍大的工程專案中都會用到。單例類保證在全域性中只有唯一乙個類的例項物件,並且在類的內部提供了獲取這個唯一例項的介面。在類中,例項化出乙個物件需要呼叫建構函式,為了防止在類的外部呼叫建構函式構造出例項,對類的建構函式就應有所限制,可以將建構函式的訪問許可權設定為private或protected。還要提供乙個訪問例項的介面,在類中定義乙個static函式,返回類內部唯一的例項物件即可。

class singleton

//防拷貝

singleton(const singleton&);

singleton& operator=(const singleton&);

public:

static singleton* getinstance() //宣告乙個靜態型別的介面來獲取例項

return _instance;

}private:

int _a;

//指向例項的指標定義為靜態私有,這樣定義靜態成員函式獲取物件例項

static singleton* _instance;

};singleton* singleton::_instance= null; //初始化靜態成員變數

建構函式能建立乙個例項物件,但是拷貝建構函式和賦值拷貝建構函式同樣可以,所以,可以用防拷貝的方法只宣告不定義,避免了多次建立例項物件。

上面的**,看起來貌似沒有什麼問題,但是若是在多執行緒下,有可能會建立多個singleton例項,所以為了防止這種情況,我們必須保證建立物件的過程時原子操作,則可以考慮加鎖。c++11的mutix標頭檔案中已經提供了lock和unlock,我們可以直接使用。

#include 

class singleton

//防拷貝

singleton(const singleton&);

singleton& operator=(const singleton&);

public:

static singleton* getinstance() //宣告乙個靜態型別的介面來獲取例項

}return _instance;

}void delinstance() //銷毀例項

}private:

int _a;

static singleton* _instance;//宣告乙個靜態成員作為類的例項

static mutex _mtx;//保證執行緒安全的互斥鎖

};singleton* singleton::_instance = null; //初始化靜態成員變數

mutex singleton::_mtx;

以上**中加了互斥鎖,保證了執行緒安全。但也不是絕對安全的,因為加鎖或解鎖會引入新的問題,有可能拋異常或者造成死鎖。解決了執行緒安全,那麼就可以進一步提高效率。在上述**中,可以看到用了兩次判斷,也叫雙檢查機制,這就保證了只在第一次獲取物件時加鎖,避免高併發場景下每次獲取例項物件都進行加鎖,提高了效率。

懶漢模式:在第一次呼叫getinstance的時候才例項化出物件,此後返回的都是該物件。相對餓漢模式而言,複雜,要確保執行緒安全問題,但在各種場景下都適用。

餓漢模式:無論是否需要該類的例項,在程式一開始的時候會產生該類的例項物件,此後返回的都是該物件。由於是在main函式之前建立執行緒,可能會出現不確定問題,適用性受到限制。

上面**實現的是懶漢模式,那麼下邊就實現餓漢模式

namespace hungry

//防拷貝

singleton(const singleton&);

singleton& operator=(const singleton&);

public:

//static singleton& getinstance()

//static singleton& getinstance() //在類內部建立靜態例項,全域性只此乙份

void delinstance() //銷毀例項

}private:

int _a;

static singleton* _instance;

};singleton* singleton::_instance = null;

//singleton* singleton::_instance = new singleton();//全域性生成乙個例項物件

}

指令流水作業時,系統可能會為了提高效率,將執行流的順序打亂,這時候進行外部的檢查時,可能內部的**還沒有完全執行完,但是已經滿足了外部的判斷條件,那麼執行就會出錯。

比如,建立乙個例項物件,正確的執行流是:

1.operator new建立空間

2.呼叫建構函式初始化成員變數

3.賦值

打亂之後的:

1.operator new建立空間

2.賦值

3.呼叫建構函式初始化成員變數

這時候為了避免這種情況,可以使用記憶體屏障memorybarrier,保證其之前和之後的順序流不被打亂。

static singleton* getinstance()

}return _instance;

}

參考:

C 執行緒安全的單例類

單例模式是一種非常常用的設計模式,幾乎在稍大的工程專案中都會用到。單例類保證在全域性中只有唯一乙個類的例項物件,並且在類的內部提供了獲取這個唯一例項的介面。在類中,例項化出乙個物件需要呼叫建構函式,為了防止在類的外部呼叫建構函式構造出例項,對類的建構函式就應有所限制,可以將建構函式的訪問許可權設定為...

C 實現執行緒安全的單例模式

廢話不多說,常用的 積澱下來。一 懶漢模式 即第一次呼叫該類例項的時候才產生乙個新的該類例項,並在以後僅返回此例項。需要用鎖,來保證其執行緒安全性 原因 多個執行緒可能進入判斷是否已經存在例項的if語句,從而non thread safety.使用double check來保證thread safe...

實現單例模式的執行緒安全的類

單例模式 是設計模式中比較簡單的一種,適合於乙個類只有乙個例項的情況,比如視窗管理,列印緩衝池和檔案系統 單例模式特點 一.確保乙個類只有乙個例項被建立 2.在不影響單例類的客戶端的情況下允許將來有多個例項,經典的模式 懶漢式,餓漢式,登記式 3.提供了乙個對全域性物件的全域性訪問指標 模式 一.懶...