執行緒同步的各種方式對比

在多執行緒程式中,往往會遇到執行緒中資源同步問題,同步問題可以劃分為兩類,一類為共享一個資源,一類為給每個執行緒分配一個資源

一:給每個執行緒分配一個資源

1:定義執行緒變數,在變數名前面加上_thread,該變數就會申明為執行緒變數

但是同時C++中對__thread變數的使用有額外的限制:

1。 在C++中,如果要在定義一個thread-local變數的時候做初始化,初始化的值必須是一個常量表達式。

2。 __thread只能修飾POD型別,即不帶自定義的構造、複製、賦值、析構的型別,不能有non-static的protected或private成員,沒有基類和虛擬函式,因此對定義class做了很多限制。但可以改為修飾class指標型別便無需考慮此限制。

2:當執行緒變數是複雜的C++類變數時,即不能申明為_thread變數

執行緒變數對於其他執行緒是可見,同時我們可以延伸出例外一種方式來代替執行緒變數

ps:A是一個類,執行緒的數量為n

A a[n];

對每個執行緒對映一個ID,執行緒1只能訪問a[1],執行緒2訪問a[2],從而達到每個執行緒訪問一個對應的一個執行緒變數

二:多個執行緒共享一個資源

多個執行緒共享一個資源涉及多種方式:訊號量,互斥量,臨界區,自旋鎖,讀寫鎖,條件變數,CAS

1:訊號量

訊號量主要用於同步,訊號量在系統中可以被任意一個執行緒釋放

三個操作:

1、一個訊號量可以初始化為非負值

2、semWait操作可以使訊號量減1,若訊號量的值為負,則執行semWait的程序被阻塞。否則程序繼續執行。

3、semSignal操作使訊號量加1。若訊號量的值小於等於0,則被semWait操作阻塞的程序講被接觸阻塞。

ps: semWait對應P原語,semSignal對應V原語。

即A執行緒呼叫 semWait,B執行緒呼叫semSignal,可以釋放A執行緒,讓A執行緒執行

2:互斥量

互斥量主要用於防止多個執行緒同時訪問同一個資源

A執行緒加鎖了,B執行緒無法釋放A執行緒加的鎖,只能等A執行緒自己釋放

3:臨界區

在多程序程式中,臨界區申明的鎖,只對當前程序有效,其他程序無效,訊號量跟互斥鎖對其他程序也是有效的,可以獲取的

4:自旋鎖

自旋鎖加鎖時不會讓出cpu,一直會處於自旋狀態去獲取鎖,互斥量跟臨界區都是會進入休眠狀態,把CPU讓出,自旋鎖適用高效能場景,加鎖時間小於執行緒切換時間

5:讀寫鎖

當執行緒A處於讀的狀態,執行緒B也可以讀,但是不能寫,當執行緒A處於寫的狀態,執行緒B則不能讀,適用與少寫多讀的場景

6:條件變數

條件變數可以同時喚醒多個執行緒,訊號量只能喚醒一個,喚醒多個執行緒的時候,通常涉及到資源競爭,往往配合互斥鎖使用

7:CAS

CAS是個原子操作,即先比較相等再替換,這個時候會產生一個ABA問題,對於這個問題可以給資料加上一個version解決