線程基礎四 使用Monitor類鎖定資源
阿新 • • 發佈:2018-12-21
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類鎖定資源