多線程同步問題

來源:互聯網
上載者:User

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

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

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

 

1:lock 關鍵字

lock 關鍵字可以用來確保代碼塊完成運行,而不會被其他線程中斷。這是通過在代碼塊運行期間為給定對象擷取互斥鎖來實現的。

lock 語句以關鍵字 lock 開頭,它有一個作為參數的對象,在該參數的後面還有一個一次只能由一個線程執行的代碼塊。例如:

C#
public void Function(){    System.Object lockThis = new System.Object();    lock(lockThis)    {        // Access thread-sensitive resources.    }}

提供給 lock 關鍵字的參數必須為基於參考型別的對象,該對象用來定義鎖的範圍。在上例中,鎖的範圍限定為此函數,因為函數外不存在任何對該對象的引用。嚴格地說,提供給 lock 的對象只是用來唯一地標識由多個線程共用的資源,所以它可以是任意類執行個體。然而,實際上,此對象通常表示需要進行線程同步的資源。例如,如果一個容器物件將被多個線程使用,則可以將該容器傳遞給 lock,而 lock 後面的同步代碼塊將訪問該容器。只要其他線程在訪問該容器前先鎖定該容器,則對該對象的訪問將是安全同步的。

通常,最好避免鎖定 public 類型或鎖定不受應用程式控制的對象執行個體。例如,如果該執行個體可以被公開訪問,則 lock(this) 可能會有問題,因為不受控制的代碼也可能會鎖定該對象。這可能導致死結,即兩個或更多個線程等待釋放同一對象。出於同樣的原因,鎖定公用資料類型(相比於對象)也可能導致問題。鎖定字串尤其危險,因為字串被公用語言運行庫 (CLR)“暫留”。這意味著整個程式中任何給定字串都只有一個執行個體,就是這同一個對象表示了所有啟動並執行應用程式定義域的所有線程中的該文本。因此,只要在應用程式進程中的任何位置處具有相同內容的字串上放置了鎖,就將鎖定應用程式中該字串的所有執行個體。因此,最好鎖定不會被暫留的私人或受保護的成員。某些類提供專門用於鎖定的成員。例如, Array 類型提供 SyncRoot。許多集合類型也提供 SyncRoot。

 

2:監視器

lock 關鍵字類似,監視器防止多個線程同時執行代碼塊。 Enter 方法允許一個且僅一個線程繼續執行後面的語句;其他所有線程都將被阻止,直到執行語句的線程調用 Exit。這與使用 lock 關鍵字一樣。事實上,lock 關鍵字就是用 Monitor 類來實現的。例如:

C# 複製代碼
lock(x){    DoSomething();}

這等效於:

C# 複製代碼
System.Object obj = (System.Object)x;System.Threading.Monitor.Enter(obj);try{    DoSomething();}finally{    System.Threading.Monitor.Exit(obj);}

使用 lock 關鍵字通常比直接使用 Monitor 類更可取,一方面是因為 lock 更簡潔,另一方面是因為 lock 確保了即使受保護的代碼引發異常,也可以釋放基礎監視器。這是通過 finally 關鍵字來實現的,無論是否引發異常它都執行關聯的代碼塊。

有關監視器的更多資訊,請參見 監視器同步技術樣本。

 同步事件和等待控制代碼

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

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

可以通過調用一種等待方法,如 WaitOne、 WaitAny 或 WaitAll,讓線程等待事件。 System.Threading.WaitHandle.WaitOne 使線程一直等待,直到單個事件變為終止狀態; System.Threading.WaitHandle.WaitAny 阻止線程,直到一個或多個指示的事件變為終止狀態; System.Threading.WaitHandle.WaitAll 阻止線程,直到所有指示的事件都變為終止狀態。當呼叫事件的 Set 方法時,事件將變為終止狀態。

在下面的樣本中,建立了一個線程,並由 Main 函數啟動該線程。新線程使用 WaitOne 方法等待一個事件。在該事件被執行 Main 函數的主線程終止之前,該線程一直處於掛起狀態。一旦該事件終止,輔助線程將返回。在本樣本中,因為事件只用於一個線程的啟用,所以使用 AutoResetEventManualResetEvent 類都可以。

C# 複製代碼
using System;using System.Threading;class ThreadingExample{    static AutoResetEvent autoEvent;    static void DoWork()    {        Console.WriteLine("   worker thread started, now waiting on event...");        autoEvent.WaitOne();        Console.WriteLine("   worker thread reactivated, now exiting...");    }    static void Main()    {        autoEvent = new AutoResetEvent(false);        Console.WriteLine("main thread starting worker thread...");        Thread t = new Thread(DoWork);        t.Start();        Console.WriteLine("main thrad sleeping for 1 second...");        Thread.Sleep(1000);        Console.WriteLine("main thread signaling worker thread...");        autoEvent.Set();    }}

3:Mutex 對象

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

當用於進程間同步時,mutex 稱為“命名 mutex”,因為它將用於另一個應用程式,因此它不能通過全域變數或靜態變數共用。必須給它指定一個名稱,才能使兩個應用程式訪問同一個 mutex 對象。

儘管 mutex 可以用於進程內的線程同步,但是使用 Monitor 通常更為可取,因為監視器是專門為 .NET Framework 而設計的,因而它可以更好地利用資源。相比之下,Mutex 類是 Win32 構造的封裝。儘管 mutex 比監視器更為強大,但是相對於 Monitor 類,它所需要的互操作轉換更消耗計算資源。有關 mutex 的用法樣本,請參見 Mutex。

C#
private Mutex mutF = new Mutex();
private void ReadF()  
{  
    mutF.WaitOne();  
   // your code to access the resource              
    mutF.ReleaseMutex();  
}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.