程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> C#的線程同步

C#的線程同步

編輯:C#入門知識

1.在單線程中,我們每次只能做一件事情。

而在多線程中,其實最本質的也是一次只能做一件事情,只是CPU給定的時間片完成之後,切換到另一個線程,然後這個分配CPU的時間片完成之後,再次切換到另一個線程,如此反復,其間切換的速度很快,給人一種同時進行的錯覺而已。

但在多線程中,往往會發生兩個線程搶占資源的問題,所以我們需要防止這些資源訪問的沖突。

C#提供線程同步機制來防止資源訪問的沖突,其中主要用到lock關鍵字、Monitor類和Mutex類



2.線程同步機制

應用程序中使用多線程的一個好處是每個線程都可以異步執行。

線程同步是指並發線程高效、有序地訪問共享資源所采用的技術。

所謂同步,是指某一時刻只有一個線程可以訪問資源,只有當資源所有者主動放棄了代碼或資源的所有權時,其他線程才可以使用這些資源



3.使用lock關鍵字實現線程同步

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

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

語法格式:

Object thisLock = new Object();

lock(thisLock){//要運行的代碼塊}

提供給lock語句的參數只是用來唯一標識由多個線程共享的資源,所以可以使任意類實例,實際上,此參數通常標識需要進行線程同步的資源。

避免鎖定public類型或不受應用程序控制的對象實例。盡量避免鎖定公共數據類型,鎖定字符串尤其危險。所以,最好鎖定不會被暫留的私有對象或受保護的對象。


說明:lock語句使用Monitor類實現,等效於try/finally語句塊,使用lock關鍵字通常比直接使用Monitor類更可取。首先,lock更簡潔;其次,lock確保了及時受保護的代碼引發異常,也可以釋放基礎監聽器,這是通過finally關鍵字來實現,無論是否引發一場,它都執行關聯的代碼塊。

注意:如果在靜態方法中使用lock關鍵字,則不能使用this

static void Main(string[] args)
{
       lock(new Program())
      { 
            Console.WriteLine("鎖定線程");
            Console.ReadLine();
       }
}



4.使用Monitor驅動對象實現線程同步

Monitor類提供了同步對對象的訪問機制,通過向單個線程授予對象鎖來控制對對象的訪問。對象鎖提供限制訪問代碼塊(臨界區)的能力。當一個線程擁有對象鎖時,其他任何線程都不能獲取該鎖。


Monitor類的主要功能:

(1)根據需要與某個對象相關聯

(2)它是未綁定的,可以直接從任何上下文調用它

(3)不能創建Monitor類的實例


Monitor類的常用方法:

Enter 在指定的對象上獲取排他鎖

Exit 釋放指定對象上的排他鎖

Pulse 通知等待隊列中的線程鎖定對象狀態的更改

PulseAll 通知所有的等待線程對象狀態的更改

TryEnter 試圖獲取指定對象的排他鎖

Wait 釋放對象上的鎖並阻止當前線程,直到它重新獲取該鎖


使用Monitor類鎖定的是對象(引用類型)而不是值類型


實例代碼:

class Program
    {
        static void Main(string[] args)
        {
            Program myProgram = new Program();		//實例化類對象
            myProgram.LockThread();					//調用鎖定線程方法
            Console.ReadLine();
        }
        void LockThread()
        {
            Monitor.Enter(this);					//鎖定當前線程
            Console.WriteLine("鎖定線程以實現線程同步");
            Monitor.Exit(this);						//釋放當前線程
        }
    }



5.使用Mutex類實現線程同步

Mutex類與監視器類似,與監視器不同的是,Mutex類可以用來是跨進程的線程同步。

使用WaitHandle.WaitOne方法請求互斥體的所屬權

擁有互斥體的線程可以在對WaitOne方法的重復調用中請求相同的互斥體而不會阻止其執行,但是記住,線程必須要調用同樣多次的ReleaseMutex方法來釋放互斥體的所屬權。

Mutex類強制線程標識,因此互斥體只能由獲得它的線程釋放。


Mutex類常用的方法

Close 在派生類中被重寫時,釋放由當前WaitHandle持有的所有資源

OpenExisting 打開現有的已命名的互斥體

ReleaseMutex 釋放Mutex一次

SignalAndWait 原子操作的形式,向一個WaitHandle發出信號並等待另一個

WaitAll 等待指定數組中的所有元素都收到信號

WaitAny 等待指定數組中的任一元素收到信號

WaitOne 在派生類中重寫,阻止當前線程,知道當前WaitHandle收到信號


實現Mutex類線程同步的步驟:

1.創建一個Mutex對象,構造函數中比較常用的有public Mutex(bool initallyOwned)

參數制定了創建該對象的線程是否希望立即獲取其所有權,當在一個資源得到保護的類中創建Mutex對象,常常將該參數設置為false

2.在需要單線程訪問的地方調用其等待方法,等待方法請求Mutex對象的所有權。如果該所有權被另一個線程擁有,則阻塞請求線程,並放到等待隊列中,請求線程將保持阻塞,直到Mutex對象受到其所有者線程發出的將其釋放的信號為止。


6.實例代碼

創建程序,自定義lockThread方法,利用Mutex對象的WaitOne方法阻止當前線程,然後再調用Mutex對象的ReleaseMutex方法釋放Mutex對象,即釋放當前線程。最後在Main方法中通過對象調用lockThread方法

class Program
    {
        static void Main(string[] args)
        {
            Program myProgram = new Program();		                //實例化類對象
            myProgram.LockThread();					//調用鎖定線程方法
            Console.ReadLine();
        }
        void lockThread()
        {
            Mutex myMutex = new Mutex(false);				//創建Mutex對象
            myMutex.WaitOne();                                          //阻止當前線程
            Console.WriteLine("鎖定線程以實現線程同步");
            myMutex.ReleaseMutex();					//釋放Mutex對象
        }
    }


總的來說,線程同步的東西還是要多讀幾遍,才能明白。而且要不斷地實踐鍛煉才能知道lock,Monitor類和Mutex類是怎麼用的,各自的區別優點以及缺點在哪裡。

感覺學無止境啊,繼續Fighting吧

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved