当第一次运行终止时,在第二次运行时未捕获到系统互斥的放弃互斥异常

本文关键字:系统 异常 放弃 终止 运行 第一次 运行时 第二次 | 更新日期: 2023-09-27 18:22:17

我创建了以下测试程序:

static void Main(string[] args)
{
    using (var mutex = new Mutex(false, "foobar"))
    {
        Console.WriteLine("Created mutex");
        try
        {
            try
            {
                if (!mutex.WaitOne(TimeSpan.FromSeconds(5), false))
                {
                    Console.WriteLine("Unable to acquire mutex");
                    Environment.Exit(0);
                }
            }
            catch (AbandonedMutexException)
            {
                Console.WriteLine("Mutex was abandoned");
            }
            Console.WriteLine("Acquired mutex - sleeping 10 seconds");
            Thread.Sleep(10000);
        }
        finally
        {
            mutex.ReleaseMutex();
            Console.WriteLine("Released mutex");
        }
    }

这个想法是,我运行程序,当线程睡眠10秒时,我通过任务管理器杀死进程。下次运行该进程时,我预计AbandonedMutexException将在WaitOne()调用中被捕获。但我并没有看到输出"Mutex被放弃"。

MSDN文档提到以下内容:

当线程放弃互斥对象时,在下一个线程中抛出异常获取互斥的线程。

然而,当我的进程被终止时(而不是同一应用程序中的另一个线程),操作系统似乎正在释放互斥锁。

有没有一种方法可以让我检测到以这种方式放弃的互斥体?

当第一次运行终止时,在第二次运行时未捕获到系统互斥的放弃互斥异常

您所观察到的是正确的行为。来自文件:

命名互斥是一个系统对象,其生存期受表示它的mutex对象的生存期限制。命名互斥是在第一个进程创建其mutex对象时创建的;在本例中,命名的互斥对象由运行该程序的第一个进程所有当表示命名互斥对象的所有互斥对象都已释放时,该互斥对象将被销毁

如果您在两个单独的进程中同时运行程序(可能会增加超时)并终止第一个进程,则可以观察您的预期行为。当第一个进程被杀死时,它会放弃互斥,这允许第二个进程获得互斥,此时它会立即抛出一个废弃的互斥异常。

如果要确定进程是否正常退出,则需要一种不同的机制。您可以通过多种方法来实现这一点,但最简单的方法之一是让进程在启动时在已知位置创建一个文件,并在优雅的清理后删除该文件。然后你可以检查该文件,如果你找到了该文件(并且没有运行程序的实例),你就知道上次关机不正常或没有成功完成。

当有多个进程使用互斥时,放弃互斥异常非常有用。如果其中一个进程被终止,另一个进程可以检测到这种情况。

但是,如果互斥体仅由一个进程使用,并且该进程被终止,则互斥体将从系统中删除(因为不再有对它的引用)。