NET多線程同步方法詳解(一):自由鎖(InterLocked)

 本文主要描述在C#中線程同步的方法。線程的基本概念網上資料也不少就再也不贅述了。直接接入主題,在多線程開發的應用中,線程同步是不可避免的。在.Net框架中,實現線程同步主要經過如下的幾種方式來實現,在MSDN的線程指南中已經講了幾種,本文結合做者實際中用到的方式一塊兒說明一下。 多線程


1. 維護自由鎖(InterLocked)實現同步 
2. 監視器(Monitor)和互斥鎖(lock) 
3. 讀寫鎖(ReadWriteLock) 
4. 系統內核對象 
1) 互斥(Mutex), 信號量(Semaphore), 事件(AutoResetEvent/ManualResetEvent) 
2) 線程池 

   除了以上的這些對象以外實現線程同步的還可使用Thread.Join方法。這種方法比較簡單,當你在第一個線程運行時想等待第二個線程執行結果,那麼你可讓第二個線程Join進來就能夠了。 

自由鎖(InterLocked) 

    對一個32位的整型數進行遞增和遞減操做來實現鎖,有人會問爲何不用++或--來操做。由於在多線程中對鎖進行操做必須是原子的,而++和--不具有這個能力。InterLocked類還提供了兩個另外的函數Exchange, CompareExchange用於實現交換和比較交換。Exchange操做會將新值設置到變量中並返回變量的原來值: int oVal = InterLocked.Exchange(ref val, 1)。 

監視器(Monitor) 

    在MSDN中對Monitor的描述是: Monitor 類經過向單個線程授予對象鎖來控制對對象的訪問。 

    Monitor類是一個靜態類所以你不能經過實例化來獲得類的對象。Monitor的成員能夠查看MSDN,基本上Monitor的效果和lock是同樣的,經過加鎖操做Enter設置臨界區,完成操做後使用Exit操做來釋放對象鎖。不過相對來講Monitor的功能更強,Moniter能夠進行測試鎖的狀態,所以你能夠控制對臨界區的訪問選擇,等待or離開, 並且Monitor還能夠在釋放鎖以前通知指定的對象,更重要的是使用Monitor能夠跨越方法來操做。Monitor提供的方法不多就只有獲取鎖的方法Enter, TryEnter;釋放鎖的方法Wait, Exit;還有消息通知方法Pulse, PulseAll。經典的Monitor操做是這樣的:
 框架


        // 通監視器來建立臨界區 
        static public void DelUser(string name)
        {
            try
            {
                // 等待線程進入 
                Monitor.Enter(Names);
                Names.Remove(name);
                Console.WriteLine("Del: {0}", Names.Count);
                Monitor.Pulse(Names);
            }
            finally
            {
                // 釋放對象鎖 
                Monitor.Exit(Names);
            }
        } 
    }ide

   其中Names是一個List<string>, 這裏有一個小技巧,若是你想聲明整個方法爲線程同步可使用方法屬性:函數

 

        // 經過屬性設置整個方法爲臨界區 
        [MethodImpl(MethodImplOptions.Synchronized)] 
        static public void AddUser(string name) 
        { 
            Names.Add(name); 
            Console.WriteLine("Add: {0}",Names.Count); 
        }測試

    對於Monitor的使用有一個方法是比較詭異的,那就是Wait方法。在MSDN中對Wait的描述是: 釋放對象上的鎖以便容許其餘線程鎖定和訪問該對象。 

    這裏提到的是先釋放鎖,那麼顯然咱們須要先獲得鎖,不然調用Wait會出現異常,因此咱們必須在Wait前面調用Enter方法或其餘獲取鎖的方法,如lock,這點很重要。對應Enter方法,Monitor給出來另外一種實現TryEnter。這兩種方法的主要區別在因而否阻塞當前線程,Enter方法在獲取不到鎖時,會阻塞當前線程直到獲得鎖。不過缺點是若是永遠得不到鎖那麼程序就會進入死鎖狀態。咱們能夠採用Wait來解決,在調用Wait時加入超時時限就能夠。spa

            if (Monitor.TryEnter(Names))
            {
                Monitor.Wait(Names, 1000); // !! 
                Names.Remove(name); 
                Console.WriteLine("Del: {0}", Names.Count);
                Monitor.Pulse(Names); 
            }  線程

相關文章
相關標籤/搜索