C 11保護共享資料的其他方法

2021-10-20 14:06:49 字數 2226 閱讀 4398

保護共享資料的初始化過程

在多執行緒程式設計中,互斥量是最通用的保護共享資料的機制。但是在某些情況下,一些資源僅需要在第一次初始化的時候需要保護,其時候就可以不需要互斥變數的保護了。比如編碼中最常見的單例模式,核心**如下:

//(3)獲得本類例項的唯一全域性訪問點

static csinglton* getinstance()

//例項已經存在,直接該例項物件

return pinstance;

}

以上**在多執行緒環境中是不安全的,有可能導致建立物件兩次,導致記憶體洩漏;如果每次訪問之前都是加鎖,將大大影響訪問效能,即使能解決問題。

為了滿足多執行緒環境中高效和安全的特性,人們提出了雙重鎖定方式單例模式,**如下:

static csinglton* getinstance()

}//例項已經存在,直接該例項物件

return pinstance;

}//執行**

getinstance()->dosomething();//步驟二

但是在實踐中可以發現,會因為指令編排方式不同,導致一些異常情況發生。

因為執行緒a中pinstance分配了指標,csinglton的建構函式還沒有執行,但此時執行緒b開始呼叫getinstance()介面,因為pinstance已經非空,直接執行dosomething(),就導致異常情況發生了。

同樣的,建立靜態區域性變數的**,在c++11之前也存在搶著建立變數的問題:

class my_class;

my_class& get_my_class_instance()

std::call_once保護共享資料

為了解決雙重鎖定以及建立多個例項的問題,c++11標準庫提供了std::once_flag和std::call_once來處理只初始化一次的情況。使用std::call_once比顯式使用互斥量消耗的資源更少,並且還是無鎖式程式設計,減少了死鎖問題的發生。

call_once和once_flag的用法:

std::once_flag flag;

void ******_do_once());}

int _tmain(int argc, _tchar* ar**)

執行結果:

****** example: called once//只有乙個列印,目標函式僅被執行一次

main thread end

如何用std::call_once建立安全性的單例模式參見這篇文章call_once 使用方法

發現問題

在正常情況下,若在執行期間call_once呼叫的函式丟擲異常,則once_flag狀態不會翻轉,其他執行緒還可以繼續執行call_once;但是在vs2013測試發現,異常無法安裝預期進行,不知道是何種原因,這裡做個記錄。

測試**:

std::once_flag flag;

void may_throw_function(bool do_throw)

std::cout << "didn't throw, call_once will not attempt again\n"; // 保證一次

}void do_once(bool do_throw)

catch (...)

}int main(int argc, _tchar* ar**)

執行結果:

vs2013編譯的程式無法繼續執行,執行緒卡住,如下

td::call_once的替代方案

在前面的文章中提到,我們也可以使用靜態區域性變數的方式建立唯一例項,只是在多執行緒環境中,存在這麼一種情況:每個執行緒都認為他們是第乙個初始化這個變數,導致這個變數被建立兩次。

但在c++11標準中,這些問題都被解決了:初始化及定義完全在乙個執行緒中發生,並且沒有其他執行緒可在初始化完成前對其進行處理,條件競爭終止於初始化階段。當然,這個要求編譯要支援c++11才可以。

std::call_once的替代方案

class my_class;

my_class& get_my_class_instance()

本文**:

保護共享資料的方法

1.關中斷 2.使用訊號量 3.禁止任務切換 關中斷是最激烈的方法。它會影響系統中所有中斷程式和其他任務的響應時間。如果關中斷則也禁止了任務切換,因為排程程式不能控制處理器切換。關中斷有兩個優點。1.它是在資料由任務 和中斷程式共享的情況下,唯一能工作的方法。因為中斷程式,不允許獲取訊號量。而禁止任...

C 11多執行緒訪問時候的資料保護例項

1 include2 include3 include 4 include5 include6 include7 include8 using namespace std 910 用成員函式作為執行緒函式的方法寫執行緒 11 std cout 是共享物件 輸出流 應該確保它不受多個執行緒的同時訪問 ...

C 學習之共享資料的保護

對於既需要共享 又需要防止改變的資料應該宣告為常型別 用const進行修飾 對於不改變物件狀態的成員函式應該宣告為常函式。1 常物件 必須進行初始化,不能被更新。const 類名 物件名 2 常成員 用const進行修飾的類成員 常資料成員和常函式成員 3 常引用 被引用的物件不能被更新。const...