服务重启后获取互斥锁时出现异常

Get an exception when acquiring mutex after a service restart

我正在用 c# 编写 windows 服务。它通过从线程调用 Read() 从 MSMQ 连续读取:

public string Read()
    {
        try
        {
            if (!readMutex.WaitOne(100))
            {
                return null;
            }
            var message = queue.Receive();
            return (string)message.Body;
        }
        catch (Exception ex)
        {
            logger.Error("Exception:" + ex);
        }
        finally
        {
            readMutex.ReleaseMutex();
        }

        return null;
    }

互斥量在 class 构造函数中创建,并在析构函数中显示 os。

问题是,在我停止并重新启动服务后,我总是在 if (!readMutex.WaitOne(100)) 第一次调用 Read() 时得到一个 AbandonedMutexException

附加调试器并添加断点后,我发现当服务停止时,finally 块永远不会进入,我不确定是否是这个问题。

这可能不是什么大问题,因为下次调用 Read() 时,将不再引发异常。但是我想知道有没有简单的方法可以解决这个问题?

追加 1 : 我发现服务停止时总是调用析构函数,所以我尝试在析构函数中释放互斥量。但是发现不允许我释放它,因为互斥量似乎是在不同的线程上下文中获取的。

追加 2: 对于对这个问题感兴趣的os,我将在检查发生了什么之后添加我发现的内容。

我测试了如果我创建一个获取互斥锁而不释放它的程序,然后close该程序,下一次程序运行仍然可以获取互斥锁成功无一例外。这和这个问题的症状是矛盾的,也和我以前的想法是矛盾的。

我认为事实是 OS close 在程序退出时为我提供互斥量,以便下次我可以获得它。

但为什么我使用此服务失败了?最后我发现我还有另一个第二个服务,它也创建了这个路径的互斥锁。第二个服务只是保留了一个互斥句柄,没有对它做任何事情(例如等待它)。在这种情况下,当我的第一个服务重新启动并尝试再次获取 Mutex 时,它会出现异常。

总之,当程序以未释放的互斥量终止时: 1) 如果互斥量也被任何其他services/applications引用,那么下次获取互斥量时,将引发异常。 2) 如果它是唯一引用这个互斥量的程序,那么 os 会为我优雅地处理这个问题,下次获取时不会报告错误。

readMutex.ReleaseMutex(); 很可能在服务关闭时永远不会被调用

更重要的是,Receive 会阻塞直到它收到一条消息,因此很可能在服务关闭时超时,认为它已挂起,并在没有正常关闭的情况下终止进程。

这里有几种方法,

你最好用 short 超时调用 MessageQueue.Receive Method (TimeSpan),并相应地调整你的逻辑,这样(关闭时)接收将有望在之前超时服务超时。

另一种方法是 运行 在线程或任务中执行此操作并在关闭时将其终止并确保调用 readMutex.ReleaseMutex()

反正你现在已经掌握了足够的信息,你应该能够以适合你的方式解决这个问题