執行緒同步的多種方式

2021-06-03 22:22:03 字數 3261 閱讀 6115

在應用程式中使用多個執行緒的乙個好處是每個執行緒都可以非同步執行。對於 windows 應用程式,耗時的任務可以在後台執行,而使應用程式視窗和控制項保持響應。對於伺服器應用程式,多執行緒處理提供了用不同執行緒處理每個傳入請求的能力。否則,在完全滿足前乙個請求之前,將無法處理每個新請求。

然而,執行緒的非同步特性意味著必須協調對資源(如檔案控制代碼、網路連線和記憶體)的訪問。否則,兩個或更多的執行緒可能在同一時間訪問相同的資源,而每個執行緒都不知道其他執行緒的操作。結果將產生不可預知的資料損壞。

對於整數資料型別的簡單操作,可以用 interlocked 類的成員來實現執行緒同步。對於其他所有資料型別和非執行緒安全的資源,只有使用本主題中的結構才能安全地執行多執行緒處理。

lock 關鍵字

lock

關鍵字可以用來確保**塊完成執行,而不會被其他執行緒中斷。這是通過在**塊執行期間為給定物件獲取互斥鎖來實現的。

lock

語句以關鍵字 lock

開頭,它有乙個作為引數的物件,在該引數的後面還有乙個一次只能由乙個執行緒執行的**塊。例如:

public class testthreading

}}

提供給 lock

關鍵字的引數必須為基於引用型別的物件,該物件用來定義鎖的範圍。在上面的示例中,鎖的範圍限定為此函式,因為函式外不存在任何對物件 lockthis 的引用。如果確實存在此類引用,鎖的範圍將擴充套件到該物件。嚴格地說,提供給 lock

的物件只是用來唯一地標識由多個執行緒共享的資源,所以它可以是任意類例項。然而,實際上,此物件通常表示需要進行執行緒同步的資源。例如,如果乙個容器物件將被多個執行緒使用,則可以將該容器傳遞給 lock,而 lock 後面的同步**塊將訪問該容器。只要其他執行緒在訪問該容器前先鎖定該容器,則對該物件的訪問將是安全同步的。

通常,最好避免鎖定 public

型別或鎖定不受應用程式控制的物件例項。例如,如果該例項可以被公開訪問,則 lock(this) 可能會有問題,因為不受控制的**也可能會鎖定該物件。這可能導致死鎖,即兩個或更多個執行緒等待釋放同一物件。出於同樣的原因,鎖定公共資料型別(相比於物件)也可能導致問題。鎖定字串尤其危險,因為字串被公共語言執行時 (clr)「暫留」。這意味著整個程式中任何給定字串都只有乙個例項,就是這同乙個物件表示了所有執行的應用程式域的所有執行緒中的該文字。因此,只要在應用程式程序中的任何位置處具有相同內容的字串上放置了鎖,就將鎖定應用程式中該字串的所有例項。因此,最好鎖定不會被暫留的私有或受保護成員。某些類提供專門用於鎖定的成員。例如,array 型別提供 syncroot。許多集合型別也提供 syncroot。

監視器與 

lock

關鍵字類似,監視器防止多個執行緒同時執行**塊。

enter

方法允許乙個且僅乙個執行緒繼續執行後面的語句;其他所有執行緒都將被阻止,直到執行語句的執行緒呼叫 

exit

。這與使用 

lock

關鍵字一樣。事實上,

lock

關鍵字就是用 

monitor

類來實現的。例如:

lock (x)

這等效於:

system.object obj = (system.object)x;

system.threading.monitor.enter(obj);

tryfinally

使用 lock

關鍵字通常比直接使用 

monitor

類更可取,一方面是因為 

lock

更簡潔,另一方面是因為 

lock

確保了即使受保護的**引發異常,也可以釋放基礎監視器。這是通過

finally

關鍵字來實現的,無論是否引發異常它都執行關聯的**塊。

同步事件和等待控制代碼

使用鎖或監視器對於防止同時執行區分執行緒的**塊很有用,但是這些構造不允許乙個執行緒向另乙個執行緒傳達事件。這需要「同步事件」,它是有兩個狀態(終止和非終止)的物件,可以用來啟用和掛起執行緒。讓執行緒等待非終止的同步事件可以將執行緒掛起,將事件狀態更改為終止可以將執行緒啟用。如果執行緒試圖等待已經終止的事件,則執行緒將繼續執行,而不會延遲。

同步事件有兩種:autoresetevent 和 manualresetevent。它們之間唯一的不同在於,無論何時,只要 autoresetevent 啟用執行緒,它的狀態將自動從終止變為非終止。相反,manualresetevent 允許它的終止狀態啟用任意多個執行緒,只有當它的 reset 方法被呼叫時才還原到非終止狀態。

可以通過呼叫 waitone、waitany 或 waitall 等中的某個等待方法使執行緒等待事件。waithandle.waitone 使執行緒一直等待,直到單個事件變為終止狀態;waithandle.waitany 阻止執行緒,直到乙個或多個指示的事件變為終止狀態;waithandle.waitall 阻止執行緒,直到所有指示的事件都變為終止狀態。當呼叫事件的 set 方法時,事件將變為終止狀態。

在下面的示例中,建立了乙個執行緒,並由 main 函式啟動該執行緒。新執行緒使用 waitone 方法等待乙個事件。在該事件被執行 main 函式的主線程終止之前,該執行緒一直處於掛起狀態。一旦該事件終止,輔助線程將返回。在本示例中,因為事件只用於乙個執行緒的啟用,所以使用 autoresetevent 或 manualresetevent 類都可以。

using system;

using system.threading;

class threadingexample

static void main()

}

mutex 物件

mutex 與監視器類似;它防止多個執行緒在某一時間同時執行某個**塊。事實上,名稱「mutex」是術語「互相排斥 (mutually exclusive)」的簡寫形式。然而與監視器不同的是,mutex 可以用來使跨程序的執行緒同步。mutex 由 mutex 類表示。

當用於程序間同步時,mutex 稱為「命名 mutex」,因為它將用於另乙個應用程式,因此它不能通過全域性變數或靜態變數共享。必須給它指定乙個名稱,才能使兩個應用程式訪問同乙個 mutex 物件。

儘管 mutex 可以用於程序內的執行緒同步,但是使用 monitor 通常更為可取,因為監視器是專門為 .net framework 而設計的,因而它可以更好地利用資源。相比之下,mutex 類是 win32 構造的包裝。儘管 mutex 比監視器更為強大,但是相對於 monitor 類,它所需要的互操作轉換更消耗計算資源。

引用:

執行緒同步的方式

一 什麼是執行緒的同步 當多個執行緒同時訪問其共享的資源時,需要相互協調,以防止出現資料不一致 不完整的問題,能達到這種狀態執行緒同步 二 執行緒同步的方式 1 互斥量 互斥鎖 如果乙個執行緒要訪問一塊資料時,它就呼叫mutex lock,如果互斥量是處於解鎖狀態,也就是說這塊資料可用,那麼就呼叫成...

執行緒的同步方式

併發 同乙個時間段有多個程式在同乙個cpu上輪流執行 並行 同一時間多個程式在不同cpu上同時執行。併發是在時間段的表象,並行是在時刻的表象。同步 執行緒之間具有依賴關係,乙個執行緒的執行依賴於另乙個執行緒的訊息。互斥 對於程序的某一共享資源,同一時刻只允許乙個執行緒訪問。互斥是一種特殊的同步。實現...

執行緒同步的方式

同步 同步就是協同步調,按預定的先後次序進行執行。如 你說完,我再說。這裡的同步千萬不要理解成那個同時進行,應是指協同 協助 互相配合。執行緒互斥 指對於共享的程序系統資源,在各單個執行緒訪問時的排它性。當有若干個執行緒都要使用某一共享資源時,任何時刻最多隻允許乙個執行緒去使用,其它要使用該資源的執...