2012-04-13 65 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