上一節主要講了建立呼叫有參(多參)函式的執行緒和執行緒池的一些內容,這一節主要講執行緒的同步。
多執行緒的出現解決了吞吐量和響應速度的問題,但同時也帶來了資源共享問題,如死鎖和資源爭用。在為單個資源分配多個執行緒可能會導致同步問題。何為執行緒同步呢?所謂同步,是指多個執行緒之間存在先後執行順序的關聯關係。如果乙個執行緒必須在另乙個執行緒完成某個工作後才能繼續執行,則必須考慮如何讓其他保持同步,以確保在系統上同時執行多個執行緒而不會出現死鎖或邏輯錯誤。
下面先看乙個例子:
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 多執行緒通訊(三)執行緒的同步
同步 當多個執行緒共享相同的記憶體時,需要每乙個執行緒看到相同的試圖,當乙個執行緒修改變數時,其他執行緒也可以讀取或修改這個變數,就需要執行緒的同步,確保他們不會訪問到無效的變數。互斥量 在變數修改時間多於以乙個儲存器訪問週期的處理器結構中,當儲存器的讀和寫這兩個週期交叉時,這種潛在的不一致性就會出...