2012-04-13 25 views
1

我不明白爲什麼.NET互斥體不會在一個等待線程中拋出AbandonedMutexException,或者在調用Mutex.Dispose()時釋放互斥體。爲什麼命名.NET互斥體在處置時拋出AbandonedMutexException?

特別是,像這樣的代碼就會死鎖:

public static void testCall() 
{ 
    using (var mutex = new System.Threading.Mutex(false, "testname")) 
    { 
     mutex.WaitOne(); 
     Console.WriteLine("second call"); 
    } 
} 

public static void Main(string[] args) 
{ 
    var thread = new System.Threading.Thread(testCall); 
    using (var mutex = new System.Threading.Mutex(false, "testname")) 
    { 
     mutex.WaitOne(); 
     Console.WriteLine("first call"); 
     thread.Start(); 
     System.Threading.Thread.Sleep(new TimeSpan(0, 0, 5)); 
     Console.WriteLine("sleep done"); 
    } 

    thread.Join(); 
} 

你要知道,我明白了AbandonedMutexException通常來自底層的WIN32互斥鎖,並在本機代碼只會在情況下被觸發所屬的線程死亡 - 我我一直在編寫C/C++代碼,並且完全瞭解底層設計。我也知道,下面的代碼是一個簡單的解決辦法:

using (var mutex = new System.Threading.Mutex(false, "testname")) 
{ 
    mutex.WaitOne(); 
    try 
    { 
     Console.WriteLine("first call"); 
     thread.Start(); 
     System.Threading.Thread.Sleep(new TimeSpan(0, 0, 1)); 
     Console.WriteLine("sleep done"); 
    } 
    finally 
    { 
     mutex.ReleaseMutex(); 
    } 
} 

我不明白的是背後的.NET互斥不會強迫釋放時,對象已經明確地佈置在佔用鎖的理由。這不會更符合.NET編程範例的其餘部分嗎?如果/當開發人員明確銷燬一個鎖定的互斥鎖時......只有將其標記爲已廢棄纔有意義。

回答

2

您可能不希望它按照您的建議工作。假設你有這個:

using (var m = new Mutex(....)) 
{ 
    m.WaitOne(); 
    // do some stuff here 
    // that ends up throwing an exception 
} 

當你的線程持有互斥量時拋出異常。如果互斥體作爲配置的一部分被釋放,那麼其他一些線程可以獲得互斥體並開始參與您正在更新的數據。除此之外,數據處於未知(可能不一致或已損壞)的狀態。

當然,最好是處理異常和清理東西,但是如果缺少我寧願互斥鎖保持(或者如果線程死亡則放棄),以便下一個嘗試獲取互斥鎖的線程知道發生了不好的事情。

除了上述內容,添加自動發佈會要求.NET包裝程序跟蹤哪個線程擁有互斥鎖。並且Dispose方法將不得不檢查該值以確定它是否應該調用ReleaseMutex。這是不可能的。 .NET程序可以將互斥量句柄傳遞給一些非託管代碼,這些代碼可以在沒有包裝器知識的情況下獲取或釋放互斥量。

所以,答案是雙重的:首先,這是不可能的。其次,即使有可能,你也可能不想要這種行爲。

+0

我不同意。如果代碼沒有處理異常,則適當的行爲是拋出'AbandonedMutexException',因爲鎖定互斥鎖的代碼由於意外行爲(例外)而丟失了它。我同意,'ReleaseMutex()'既不明智又有點過分,但'AbandonedMutexException'是有道理的。 – 2012-04-13 22:08:22

+0

但是如果線程沒有退出,那麼這個互斥就不會被放棄。 – 2012-04-13 23:12:21

+0

不,不是在放棄的WIN32意義上..但是你不會在你的例子中說如果拋出一個異常並且沒有處理*和*這個互斥體被拋棄了,認爲這個互斥體被拋棄了嗎? 「 – 2012-04-13 23:16:06

相關問題