使用Monitor類鎖定資源

class Program
{
    static void LockTooMuch(object lock1, object lock2)
    {
        lock(lock1)
        {
            Thread.Sleep(1000);
            lock(lock2);
        }
    }

    static void Main()
    {
        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 acquired a resource!");
            }
        }

        new Thread(() => LockTooMuch(lock1, lock2)).Start();

        Console.WriteLine("---------------------------------");
        lock(lock2)
        {
            Console.WriteLine("This will be a deadloock");
            Thread.Sleep(1000);
            lock(lock1)
            {
                Console.WriteLine("Acquired a protected resource successfully");
            }
        }
    }
}

工作原理

先看看LockTooMuch方法。在該方法中,我們先鎖定第一個對象,等待一秒後鎖定了第二個對象。然後在另一個線程中啓動該方法。最後嘗試在主線程中先後鎖定第二個和第一個對象。

如果像該示例的第二部分一樣使用lock關鍵字,將會造成死鎖。第一個線程保持對lock1對象的鎖定,等待直到lock2對象被釋放。主線程保持對lock2對象的鎖定並等待直到lock對象被釋放,但lock1對象永遠不會被釋放。

實際上lock關鍵字是Monitor類用例的一個語法糖。如果我們分解使用了lock關鍵字的代碼,將會看到它如下面代碼片段表示:

bool acquiredLock = false;
try
{
    Monitor.Enter(lockObject, ref acquiredLock);

    //Code that accesses resources that are protected by lock.
}
finally
{
    if(acquiredLock)
    {
        Monitor.Exit(lockObject);
    }
}

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

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