C# 在服务重新启动后获取互斥时获取异常

C# 在服务重新启动后获取互斥时获取异常,c#,mutex,C#,Mutex,我正在用c#编写一个windows服务。它通过从线程调用Read()连续读取MSMQ: public string Read() { try { if (!readMutex.WaitOne(100)) { return null; } var message = queue.Receive(); retu

我正在用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;
    }
互斥锁在类构造函数中创建,并在析构函数中释放

问题是,在我停止并重新启动服务后,如果(!readMutex.WaitOne(100))第一次调用
Read()
时,我总是在
处得到一个
放弃的MutexException

在附加调试器并添加断点后,我发现当服务停止时,
finally
块从未被输入,我不确定这是否是问题所在

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

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

附加2: 对于那些对这个问题感兴趣的人,我将在检查发生了什么之后补充我的发现

我测试过,如果我创建了一个在不释放互斥锁的情况下获取互斥锁的程序,然后关闭该程序,下次程序运行时,它仍然可以毫无例外地成功获取互斥锁。这与这个问题的症状相矛盾,也与我过去的想法相矛盾

我认为事实是,当程序退出时,操作系统会为我关闭互斥锁,所以下次我可以获得它

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

总之,当程序以未释放的互斥终止时: 1) 如果互斥体也被任何其他服务/应用程序引用,那么下次获取互斥体时,将引发异常。
2) 如果它是唯一引用此互斥体的程序,那么操作系统将为我优雅地处理此互斥体,并且在下一次采集时不会报告任何错误。

readMutex.ReleaseMutex()很可能在服务关闭时从未被调用

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

这里有几种方法

您最好调用
MessageQueue.Receive方法(TimeSpan)
,并使用short超时,并相应地调整您的逻辑,这样(关闭时)接收将在服务超时之前超时

另一种方法是在线程或任务中运行它,并在关机时终止它,确保调用
readMutex.ReleaseMutex()


不管怎样,您现在已经有了足够的信息,您应该能够以适合您的方式解决这一问题。第一种方法是:我发现服务停止时没有任何超时,因此我假设系统不会等待
receive()
超时,但可能会将其杀死。因此,在这段时间内,服务仍有可能停止。我认为这不是一个可靠的解决方案。第二,请您提供更多关于在何处实施该版本的信息,好吗?目前,消息读取部分是其他服务引用的一个独立模块,更改机制意味着大量工作。因此,我真的希望有一种更简单的方法。@mosakashaka没有看到您是如何构建它的,很难给出更多建议。然而,我认为您现在已经意识到了这个问题,
readMutex.ReleaseMutex()
需要以某种方式调用。我不确定问题是否是因为从未调用过
readMutex.ReleaseMutex()
。现在我没有办法让
readMutex。ReleaseMutex()
总是在服务站调用…@mosakashaka记录并向自己证明这是一个XY问题吗?互斥锁的作用是什么?你考虑过异步读取MSMQ吗?@MickyD抱歉,我不太明白XY问题是什么。我在这里使用
Mutex
以避免多个读取器同时读取队列。@MickyD此读取由项目的许多部分调用,因此我不想修改其机制,比如将其更改为基于事件的。。。另外,我读到
BeginReceive
EndReceive
不是线程安全的。我确实同意,我不知道为什么会有互斥锁,只要使用锁就行了?