为什么不';t命名的.NET互斥体在释放时抛出废弃的MutexException?

为什么不';t命名的.NET互斥体在释放时抛出废弃的MutexException?,.net,synchronization,mutex,abandonedmutexexception,.net,Synchronization,Mutex,Abandonedmutexexception,我不明白为什么.NET互斥体既不在一个等待线程中抛出放弃的MutexException,也不在调用mutex.Dispose()时释放互斥体 特别是,这样的代码会死锁: public static void testCall() { using (var mutex = new System.Threading.Mutex(false, "testname")) { mutex.WaitOne(); Console.WriteLine("secon

我不明白为什么.NET互斥体既不在一个等待线程中抛出
放弃的MutexException
,也不在调用
mutex.Dispose()
时释放互斥体

特别是,这样的代码会死锁:

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();
}
请注意,我理解
废弃的mutexception
通常来自底层的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编程范式的其他部分吗?如果/当开发人员显式销毁锁定的互斥锁时。。。只有将其标记为废弃才有意义。

您可能不希望它按照您建议的方式工作。假设你有:

using (var m = new Mutex(....))
{
    m.WaitOne();
    // do some stuff here
    // that ends up throwing an exception
}
线程持有互斥锁时引发异常。如果互斥体作为dispose的一部分被释放,那么其他一些线程可以获得互斥体并开始共享您正在更新的数据。但现在数据处于未知(可能不一致或损坏)状态

当然,最好是处理异常并清理问题,但如果没有,我宁愿保持互斥锁(或者在线程死亡时放弃互斥锁),以便下一个尝试获取互斥锁的线程知道发生了什么不好的事情

除上述内容外,添加自动发布还需要.NET包装器跟踪哪个线程拥有互斥锁。而
Dispose
方法必须检查该值,以确定是否应该调用
ReleaseMutex
。而这是不可能跟踪的。NET程序可以将互斥锁句柄传递给一些非托管代码,这些代码可以在包装器不知情的情况下获取或释放互斥锁


因此,答案有两个:第一,这是不可能的。第二,即使有可能,你也可能不想要那种行为。

我不同意。如果代码没有处理异常,则适当的行为是抛出一个
放弃的mutexception
,因为锁定互斥锁的代码由于意外行为(异常)而丢失了互斥锁。我同意,
ReleaseMutex()
既不明智又有点过分,但是
弃用MutexException
是有道理的。但是如果线程不退出,那么互斥就不会被弃用。不,不是在WIN32中弃用的意思。。但是,在你的例子中,你不是说如果一个异常被抛出,没有处理,并且互斥体被处理,那么考虑互斥体“被放弃”是不是不正确的?“是的,我会考虑互斥体“被放弃”,但是底层对象是Win32互斥体,如果线程在互斥体上仍然有锁,它就被“废弃”了。如果线程没有死,就没有被放弃的互斥。我们已经确定释放互斥锁是不明智的,而且可能不可能,所以我们仍然坚持现有的行为。