1. 程式人生 > >線程基礎四 使用Monitor類鎖定資源

線程基礎四 使用Monitor類鎖定資源

timeout 第二部分 接受 ons The rgs 代碼片段 一秒 dea

  前面我們講過了lock的用法以及競爭條件導致的錯誤,實際上lock關鍵字是Monitor類用例的一個語法糖。如果我們分解使用了lock關鍵字的代碼,將會看到它如下面代碼片段所示:

    bool acquireLock = false;
    try
    {
        Monitor.Enter(lockObject, ref acquireLock);
        //Code that access resources that are protected by the lock.
    }
    finally
    {
        if (acquireLock)
        {
            Monitor.Exit(acquireLock);
        }
    }

  在多線程編程中另一個常見的多線程錯誤被稱為死鎖(deadlock)。在以下例子中,將演示使用Monitor類來避免死鎖,而之前描述過得lock用於創建死鎖。

        static void Main(string[] args)
        {
            object lock1 = new object();
            object lock2 = new object();
            new Thread(() => LockTooMuch(lock1, lock2)).Start();

            lock
(lock2) { Thread.Sleep(1000); Console.WriteLine(@"Monitor.TryEnter allows not to get stuck,returning false after a specified timeout is elapsed"); if (Monitor.TryEnter(lock1, TimeSpan.FromSeconds(5))) { Console.WriteLine(
"Acquired a protected resource successfully"); } else { Console.WriteLine("Timeout acquiring a resource!"); } } new Thread(() => LockTooMuch(lock1, lock2)).Start(); Console.WriteLine("-----------------------------"); lock (lock2) { Console.WriteLine("This will be a deadlock"); Thread.Sleep(1000); lock (lock1) { Console.WriteLine("Acquired a protected resouce successfully"); } } } static void LockTooMuch(object lock1, object lock2) { lock (lock1) { Thread.Sleep(1000); lock (lock2) ; } }

技術分享圖片

  在這個例子中,先定義了一個LockTooMuch方法。在該方法中,我們先鎖定了第一個對象,等待一秒後鎖定了第二個對象。然後在另一個線程中啟動該方法。最後嘗試在主線程中先後鎖定第二個和第一個對象。我們分為兩部分,分別使用Montitor以及lock演示了如何避免死鎖以及造成死鎖。

  首先先說說造成死鎖的情況,在第二部分中,我們使用了lock關鍵字。通過new Thread新起的線程使得程序保持對lock1對象的鎖定,等待直到lock2對象被釋放。而此時主線程卻又在保持對lock2對象的鎖定並等待直到lock1對象被釋放,但lock1卻被新起的線程占用,等待lock2,因此lock1對象永遠不會被釋放,從而進入死鎖狀態。

  因此,我們就可以通過第一部分的方式,采用Monitor類的TryEnter方法,該方法接受一個超時參數。如果我們不能在超市參數過期之前獲取到被lock保護的資源,則該方法返回false。

  

線程基礎四 使用Monitor類鎖定資源