C#死鎖示例


死鎖的產生

什么是死鎖:

所謂死鎖,是指多個進程在運行過程中因爭奪資源而造成的一種僵局,當進程處於這種僵持狀態時,若無外力作用,它們都將無法再向前推進。 因此我們舉個例子來描述,如果此時有一個線程A,按照先鎖a再獲得鎖b的的順序獲得鎖,而在此同時又有另外一個線程B,按照先鎖b再鎖a的順序獲得鎖。如下圖所示

產生死鎖的原因

競爭資源

系統中的資源可以分為兩類:

  1. 競爭不可剝奪資源(例如:系統中只有一台打印機,可供進程P1使用,假定P1已占用了打印機,若P2繼續要求打印機打印將阻塞)
  2. 是競爭臨時資源(臨時資源包括硬件中斷、信號、消息、緩沖區內的消息等),通常消息通信順序進行不當,則會產生死鎖

進程間推進順序非法

1. 若P1保持了資源R1,P2保持了資源R2,系統處於不安全狀態,因為這兩個進程再向前推進,便可能發生死鎖
2. 例如,當P1運行到P1:Request(R2)時,將因R2已被P2占用而阻塞;當P2運行到P2:Request(R1)時,也將因R1已被P1占用而阻塞,於是發生進程死鎖

一個死鎖的例子

static void LockTooMuch(object lock1, object lock2)
        {
            lock (lock1)  //鎖定lock1對象
            {
                Thread.Sleep(1000); //線程掛起1s
                lock (lock2) //試圖獲取lock2對象的鎖定
                {
                    Console.WriteLine("成功獲取到lock2對象的鎖定");
                }
            }
        }

        /// <summary>
        /// 造成一個死鎖
        /// </summary>
        public static void Test()
        {
            //定義兩個鎖定對象
            object lock1 = new object();
            object lock2 = new object();

            //開啟線程
            Thread t1 = new Thread(() => {LockTooMuch(lock1,lock2); });
            t1.Start();

            //在主線程中鎖定lock2對象
            lock (lock2)
            {
                Console.WriteLine("這將要產生一個死鎖");
                Thread.Sleep(1000);
                lock (lock1)  //試圖訪問lock1
                {
                    Console.WriteLine("成功獲取到lock1對象的鎖定");
                }
            }
        }

通過Monitor的超時鎖定機制避免死鎖

直接使用Monitor類。其擁有TryEnter方法,該方法接受一個超時參數。如果在我們能夠獲取被lock保護的資源之前,超時參數過期,則該方法會返回 false.

/// <summary>
        /// 使用Monitor避免死鎖
        /// </summary>
        public static void Test2()
        {
            //定義兩個鎖定對象
            object lock1 = new object();
            object lock2 = new object();

            //開啟線程
            Thread t1 = new Thread(() => {LockTooMuch(lock1,lock2); });
            t1.Start();

            //在主線程中使用Monitor類來鎖定lock2對象
            //在主線程中鎖定lock2對象
            lock (lock2)
            {
                Console.WriteLine("使用Monitor.TryEnter避免死鎖,有一個超時時間的設定 超時返回false");
                Thread.Sleep(1000);
                //設置5s的超時時間
                if(Monitor.TryEnter(lock1,TimeSpan.FromSeconds(5)))
                {
                    Console.WriteLine("成功獲取到lock1對象的鎖定");
                }
                else
                {
                    Console.WriteLine("獲取lock1對象失敗,");
                }
            }
        }

源自:C#多線程學習總結


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM