C# 在服务重新启动后获取互斥时获取异常
我正在用c#编写一个windows服务。它通过从线程调用C# 在服务重新启动后获取互斥时获取异常,c#,mutex,C#,Mutex,我正在用c#编写一个windows服务。它通过从线程调用Read()连续读取MSMQ: public string Read() { try { if (!readMutex.WaitOne(100)) { return null; } var message = queue.Receive(); retu
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
不是线程安全的。我确实同意,我不知道为什么会有互斥锁,只要使用锁就行了?