怎樣編寫安全的多線程C#程序

 與多線程相關的兩個常見的需要解決的問題是:臨界資源保護和線程間的同步依賴,每一種語言都提供了自己的一套設施(有的語言可能需要藉助OS的API)來解決這兩個問題,C#提供了更方便靈活的解決方案,首先C#可以允許我們在不同的級別上加鎖,也就是說我們可以控制加鎖的粒度。其次,C#提供了一套內置的線程安全的容器,方便我們的使用。

    一.不同級別(Level)上的同步:
    1.object level 同步
    對應的class必須從ContextBoundObjectpdf繼承(同步上下文context,使所有的方法調用能被截獲),並且在class上運用SynchronizationAttribute 。

    2.Method level 同步
    System.Runtime.CompilerServicepdf空間包含的一些屬性將影響CLR在運行期間的行爲。特性MethodImplAttribute可以用於需要進行同步控制的方法上。

    3.code segment level 同步
    (1)Monitor類(主要是靜態方法) 

Monitor.Enter(obj)//獲得加在對象obj上的鎖 ... Monitor.Exit(obj)//釋放鎖 //上面兩句之間的代碼相當於lock(obj){...} Monitor.TryEnter(obj)//該方法立即返回,如果返回值爲false,則接下來不需要Monitor.Exit(obj)。 //以下幾個方法用於線程間的交互 ==》 解決同步依賴 Monitor.Wait(obj)//等待脈衝消息。釋放對象上的鎖並阻塞當前線程,以後只有其它線程調用Pulse或PulseAll時纔會給它再次獲得鎖的機會 Monitor.Pulse(obj)//發射脈衝消息( 只有得到鎖後才能發射,而且發射不會自動釋放鎖) Monitor.PulseAll(obj)

    注意:
    (1)Monitor 鎖定對象,只能在Enter()和Exit()之間的代碼塊中調用Wait和Pulse
    (2)不能在一個線程中獲得鎖,而在另一個線程中釋放鎖。這樣會產生鎖丟失。 獲得鎖和釋放鎖應該在同一個線程中完成。
    (3)lock語句

lock(obj) { 需要進行同步的代碼 }

    (4)ReaderWriterLock類
    實現單寫多讀程序的鎖。

AcquireReaderLock()//當沒有寫程序線程佔用鎖時,就可獲得鎖 AcquireWriterLock()//當沒有任何讀寫程序線程佔用鎖時,纔可獲得鎖 ReleaseReaderLock() ReleaseWriterLock()

     (5)ManualResetEvent

Set()方法將狀態設置爲有信號 Reset()將其設置爲無信號 WaitOne()將阻塞到其有信號爲止,若調用WaitOne的時刻就是有信號的,將不會阻塞

    (6)AutoResetEvent
    與ManualResetEvent的區別是pdf,AutoResetEvent.WaitOne()會自動改變事件對象的狀態,即AutoResetEvent.WaitOne()每執行一次,事件的狀態就改變一次。有信號-->無信號;無信號-->有信號

    說明:
    (1)無論是Monitor還是lock、ReaderWriterLock都只對引用類型的對象有效,因爲引用類型的對象有一個隱藏的sync#字段,該字段的作用就是作爲加鎖的標記。
    (2)上述的各種設施中,只有Monitor 和ManualResetEvent/AutoResetEvent 能解決線程間的同步依賴問題,而其它的設施主要用於解決臨界資源共享。

    4.member level同步
    (1)Interlocked類(主要是靜態方法)
    同步一個由許多線程共享的變量。

Decrement(ref int);//使變量減1 Increment(ref int);//使變量加1 //以上兩個方法僅針對類int變量 Exchange(ref object, object);

    (2)ThreadStaticAttribute pdf
    該特性用於修飾靜態變量,被該特性修飾的靜態變量在每個線程中都有自己的副本。

    二.創建線程安全的對象

Hashtable h = Hashtable.Synchronized(new Hashtable()) ;

    ArrayList等容器也提供類似操作。

1
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章