執行緒實用解析 (三)執行緒的同步

2021-06-09 23:33:58 字數 3353 閱讀 6545

上一節主要講了建立呼叫有參(多參)函式的執行緒和執行緒池的一些內容,這一節主要講執行緒的同步。

多執行緒的出現解決了吞吐量和響應速度的問題,但同時也帶來了資源共享問題,如死鎖和資源爭用。在為單個資源分配多個執行緒可能會導致同步問題。何為執行緒同步呢?所謂同步,是指多個執行緒之間存在先後執行順序的關聯關係。如果乙個執行緒必須在另乙個執行緒完成某個工作後才能繼續執行,則必須考慮如何讓其他保持同步,以確保在系統上同時執行多個執行緒而不會出現死鎖或邏輯錯誤。

下面先看乙個例子:

class program

static bool biaoji = false;

static void testshow()

}static void testshow1()

} 這個程式很簡單,就是建立兩個執行緒,分別呼叫兩個函式輸出一句話,兩個函式都共用到了乙個全域性變數biaoji

,在testshow

()裡邊將

biaoji

的值改為

false

,執行之後的結果如下:

或者出現第一種結果原因,我們在testshow

裡將biaoji

值改為true

,在testshow1

裡執行if

(biaoji

)時為biaoji

值為true

,所以可以輸出兩句話。

出現第二句話的原因在於,兩個執行緒同時訪問biaoji

值,此時

biaoji

值為發生變化,仍未

false

,故在執行

testshow1

時biaoji

值仍為false

,所以只能輸出一句話

這裡就出現了執行緒的同步問題,結果一是我們想要的結果,但是在程式的執行過程中,往往會出現像結果二那樣的結果。

如果解決這樣的問題呢?為了解決這些問題,system.threading

命名空間提供了多個用於同步執行緒的類。這些類包括

mutex,monitor,interlocked,autoresetevent. 下面會逐步介紹一些解決同步的方法。

一、最簡單也是最常用的方法,c#

提供的lock

方法lock

關鍵字能確保當乙個執行緒位於**的臨界區時,另乙個執行緒不進入臨界區。如果其他執行緒試圖進入鎖定的**段,則它將一直等待,

直到鎖定的物件被釋放以後才能進入臨界區。

下面演示下如何使用lock:

**如下:

private static readonly object obj=new object(); s

tatic void testshow() }

}這樣不管怎麼呼叫顯示的結果永遠都是上例所示的第一種結果。

lock使用方法:

lock關鍵字將語句塊標記為臨界區,方法是獲取給定物件的互斥鎖,執行語句,然後釋放該鎖。 此語句的形式如下:

object obj = new object();

lock (obj)

lock注意事項:

最佳做法是定義 private 

物件來鎖定

, 或 

private static 

物件變數來保護所有例項所共有的資料,鎖定的物件不能為空。

二、monitor類

lock語句經過編譯器解析為

monitor

類。monitor

類的效果和

lock

基本是一樣的。

可以通過以下方式實現同步:

lock方式: 

lock

(obj){

//code section}

monitor類(為靜態類):   

monitor.enter(obj);

//code section

//........

monitor.exit(obj);

示例:static void testshow()

monitor.exit(obj); }

除此之外monitor

還有乙個優點就是可以設定乙個等待獲得鎖定的超時值,用以避免無限期的鎖定。通過

monitor.tryenter(object obj

,timespan time)

來設定等待獲得鎖定的最長時間

使用示例:

if(monitor.tryenter(obj,1000))

finally

例項:

static void testshow()

}catch   } }

這樣因為執行緒在修改biaoji

值時,休眠的

3秒,超出了

monitor

設定的等待時間,所以另乙個執行緒已經開始執行了,執行時在函式

testshow1

()中,

biaoji

的值仍為

false

所以只輸出了一句話。等到

2個執行緒都執行完畢時,此時

biaoji

的值為true

。三、mutex

mutex的功能和c# 中的lock一樣,不同的是它可以跨程序。在作業系統中,許多執行緒常常需要共享資源,而這些資源往往要求一次只能為乙個執行緒服務,這種排他性地使用共享資源稱為執行緒間的互斥。執行緒互斥實質上也是同步,可以看做一種特殊的執行緒同步。但是,進入和釋放乙個mutex

要花費幾毫秒,效率會比較低。

通常我們會使用乙個mutex

的例項,呼叫

waitone

方法來獲取鎖,

releasemutex

方法來釋放鎖。

方法如下:

mutex m = new mutex();

m.waitone();

//code section

//...

m.releasemutex();

此外我們還可以為waitone

()函式設定引數,以防止無限期的等待。

mutex類還有一些其他的方法:比如:

mutex的

waitall()

函式//等待所有的執行緒操作

mutex的

waitany()

函式//多個操作時,等待指定的某個執行緒操作

但是在操作結束後,一定要分別進行釋放。

今天到這裡基本上就這些了,當然這些都是比較常用的解決執行緒同步的方法,還有其他的一些方法比如autoresetevent 、manualresetevent 、 eventwaithandle ,還有乙個volatile關鍵字的同步方法,但是它只能在變數一級做同步。關於後邊的上邊所列的同步方法不常用,所以就不再做介紹了,有興趣的朋友可以自己去了解下。希望可以對大家有所幫助。下一節會講一下非同步操作。

OpenMP(三) 執行緒同步

1.引言 在openmp中,執行緒同步機制包括互斥鎖同步機制和事件同步機制。2.互斥鎖同步 互斥鎖同步的概念類似於windows中的臨界區 criticalsection 以及windows和linux中的mutex以及vxworks中的semtake和semgive 初始化時訊號量為滿 即對某一塊...

多執行緒小結(三)執行緒同步總結

一般來說,執行緒同步比較讓人糾結的地方在於它是許多執行緒共用一段 的,而且什麼時候誰用誰不用,也基本是不可控制不可預料的,那麼對於它們可能會同時訪問並更改的資料,就需要加鎖了。加鎖就是將一段 變為臨界區 一段在同一時候只被乙個執行緒進入 執行的 加鎖的方式一般有兩種,lock關鍵字 c 提供lock...

linux 多執行緒通訊(三)執行緒的同步

同步 當多個執行緒共享相同的記憶體時,需要每乙個執行緒看到相同的試圖,當乙個執行緒修改變數時,其他執行緒也可以讀取或修改這個變數,就需要執行緒的同步,確保他們不會訪問到無效的變數。互斥量 在變數修改時間多於以乙個儲存器訪問週期的處理器結構中,當儲存器的讀和寫這兩個週期交叉時,這種潛在的不一致性就會出...