C# 多線程之線程同步

來源:互聯網
上載者:User

標籤:lin   struct   需要   release   one   否則   art   被鎖   async   

多線程間應盡量避免同步問題,最好不要線程間共用資料。如果必須要共用資料,就需要使用同步技術,確保一次只有一個線程訪問和改變共用狀態。

一::lock語句

lock語句事設定鎖定和接觸鎖定的一種簡單方法。其文法非常簡單:

            lock (obj)            {                // 需要發生同步的代碼區            }

將共用資料的作業碼,放在上述的“{...}”地區內。鎖定的對象(obj)必須是參考型別,如果鎖定一個實值型別,實際是鎖定了它的一個副本,並沒有實現鎖定功能。

一般地,被鎖定對象需要被建立為 私人 唯讀 參考型別:

        private readonly object obj = new object();

二::Interlocked類

Interlocked類用於使變數的簡單語句原子化。它提供了以安全執行緒的方式遞增、遞減、交換和讀取值的方法。

        private int stateFlag = 0;        public int IncrementState        {            //get            //{            //    lock (this)            //    {            //        stateFlag++;            //        return stateFlag;            //    }            //}            get            {                return Interlocked.Increment(ref stateFlag); // using System.Threading;                //Interlocked.Decrement(ref V0);                //Interlocked.Exchange(ref V1, ref V2);                //Interlocked.Read(ref V0);            }        }

三::Monitor類

與lock相似,C#的lock語句被編譯器解析為使用Monitor類。鎖定開始相當於 Monitor.Enter(obj) 方法,該方法會一直等待,直到線程被對象鎖定。解除鎖定後線程進入同步階段,使用 Monitor.Exit(obj)方法解除鎖定,編譯器將它與try塊的finally結合。方法一中的代碼,相當於:

            Monitor.Enter(obj);            try            {                // 需要發生同步的代碼區            }            finally            {                Monitor.Exit(obj);            }

與lock語句相比,Monitor類的優點在於:可以添加一個等待北鎖定的逾時值。這樣就不會無限期等待被鎖定,而可以使用 TryEnter() 方法,給一個逾時參數。

            bool lockTaken = false;            Monitor.TryEnter(obj, 500, ref lockTaken);            if (lockTaken)            {                try                {                    // acquired the lock                    // synchronized region for obj                }                finally                {                    Monitor.Exit(obj);                }            }            else            {                // didn‘t get the lock,do something else            }

如果obj被鎖定,TryEnter() 方法就會把 bool 型引用參數 lockTaken 設定為 true,並同步地訪問由 obj 鎖定的狀態。如果另一線程 鎖定 obj 的時間超過 500 毫秒,Try Enter() 方法就把變數 lockTaken 設為 false ,線程不再等待,而是用於執行其它操作。也許在之後,該線程會嘗試再次被鎖定。

 四::SpinLock結構

它是一個結構體(struct),用法極類似於Monitor類。獲得鎖用 Enter()或TryEnter() 方法,釋放鎖用 Exit() 方法。它還提供了屬性 IsHeld 和 IsHeldByCurrentThred ,指定當前是否被鎖定。

        SpinLock mSpinLock = new SpinLock(); // 最好只是用一個 SpinLock        public void fun1()        {            // .....            bool lockTaken = false;            mSpinLock.Enter(ref lockTaken);            try            {                // synchronized region            }            finally            {                mSpinLock.Exit();            }            // ...        }        public void fun2()        {            // .....            bool lockTaken = false;            mSpinLock.TryEnter(500, ref lockTaken);            if (lockTaken)            {                try                {                    // synchronized region                }                finally                {                    mSpinLock.Exit();                }            }            else            {                // didn‘t get the lock,do something else            }            // ...        }

SpinLock結構體是 .Net 4 新增。它適用於:有大量的鎖,且鎖定時間都非常短。程式需要避免使用多個 SpinLock 結構,也不要調用任何可能阻塞的內容。

五::WaitHandle 基類

WaitHandle是一個抽象基類,用於等待一個訊號的設定。可以等待不同的訊號,因為WaitHandle是一個基類,可以從中派生一些類。

        public delegate int TakesAWhileDelegate(int data, int ms); // 聲明委託        public void Main()        {            TakesAWhileDelegate vTAwdl = TakesAWhile;            IAsyncResult vAr = vTAwdl.BeginInvoke(1, 3000, null, null);            while(true)            {                Console.Write(".");                if (vAr.AsyncWaitHandle.WaitOne(300, false)) // 等待 vAr.AsyncWaitHandle 收到訊號(逾時300毫秒)                {                    Console.WriteLine("Can get the result now.");                    break;                }            }            int result = vTAwdl.EndInvoke(vAr);            Console.WriteLine("Result:{0}", result);
Console.Read(); } int TakesAWhile(int data, int ms) { Console.WriteLine("TakesAWhile started"); Thread.Sleep(ms); Console.WriteLine("TakesAWhile completed"); return ++data; }

以上執行個體代碼,使用”非同步委託", BeginInvoke() 方法返回一個實現了 IAsycResult介面的對象。使用 IAsycResult 介面,可以用AsycResult屬性訪問 WaitHandle 基類。在調用WaitOne()方法時,線程等待一個與等待控制代碼相關的訊號。

使用 WaitHandle 類可以等待一個訊號出現(WaitOne()方法)、等待必鬚髮出訊號的多個對象(WaitAll()方法)、或者等待多個對象中的一個(WaitAny()方法)。後兩者事WaitHandle類的靜態方法,接收一個WaitHandle參數數組。

六::Mutex類

Mutex(mutual exclusion,互斥)是 .NET Framework中提供跨多個進程同步訪問的一個類。所以,它常被用於“程式單一啟動控制”。

        /// <summary>        /// 單一進程 檢查,如果已經運行一個進程,返回false,表示檢查不通過。否則返回true。        /// </summary>        /// <returns></returns>        private bool RunOnceCheck()        {            bool vExist;            Mutex nMutex = new Mutex(false, "SingletonWinAppMutex", out vExist);            if (!vExist)            {                // 表示已經啟動一個了,應退出當前啟動                return false;            }            return true;        }

它非常類似於Monitor類,因為他們都只有一個線程能擁有鎖定。只有一個線程能獲得互斥鎖定,訪問受互斥保護的同步代碼地區。Mutex派生自基類WaitHandle,因此可以利用WaitOne()方法獲得互斥鎖定,在該過程中成為該互斥的擁有者。調用 ReleaseMutex()方法,釋放互斥。

            bool createdNew;            Mutex mutex = new Mutex(false, "ProCSharpMutex", out createdNew);            if (mutex.WaitOne())            {                try                {                    // synchronized region                }                finally                {                    mutex.ReleaseMutex();                }            }            else            {                // some problem happened while waiting            }

七::Semaphore類

 Semaphore非常類似於互斥,其區別在於Semaphore可以同時由多個線程使用。它是一種計數互斥鎖定,可以定義允許同時訪問受其鎖定保護的資源的線程個數。它適用於:有許多可用資源,且只允許一定數量的線程訪問該資源。

八::Events類

它是一種可以在系統範圍內同步資源的方法。

九::Barrier類

它非常適用於其中工作有很多個任務分支且以後又需要合并工作的情況。

十::ReaderWriterLockSlim類

為了使鎖定機制允許鎖定多個讀取器(而不是一個寫入器)訪問某個資源,可以使用此類。它提供了一個鎖定功能,如果沒有寫入器鎖定資源,就允許多個讀取器訪問資源,但只能有一個寫入器鎖定該資源。

 

 

 

C# 多線程之線程同步

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.