我正在用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;
}
互斥锁是在类构造函数中创建的,并放置在析构函数中。
问题在于,在我停止并重新启动服务后,总是在第一次调用AbandonedMutexException
时在if (!readMutex.WaitOne(100))
处收到Read()
。
在附加调试器并添加断点之后,我发现当服务停止时,永远不会输入finally
块,我不确定这是否是问题所在。
这可能不是一个大问题,因为下次调用Read()
时,不再引发异常。但是我想知道是否有一种简单的方法可以解决这个问题?
追加1 : 我发现在服务停止时总是调用析构函数,因此我尝试在析构函数中释放互斥量。但是发现我不允许发布它,因为互斥锁似乎是在不同的线程上下文中获取的。
附加2 : 对于那些对此问题感兴趣的人,我将在检查发生了什么之后添加发现的内容。
我测试过,如果我创建一个无需释放互斥量就获取互斥量的程序,然后关闭该程序,则在下次运行该程序时,它仍然可以毫无例外地成功获取互斥量。这与该问题的症状相矛盾,也与我以前的想法相矛盾。
我认为事实是,当程序退出时,操作系统会为我关闭互斥锁,因此下次可以获取它。
但是为什么我的这项服务失败了?最终,我发现我还有另一个服务,它也创建了该路径的互斥体。第二个服务只是保留了一个互斥锁句柄,而没有对其进行任何操作(例如,等待它)。在这种情况下,当我的第一个服务重新启动并尝试再次获取Mutex时,它将获得异常。
最后,当程序以未发布的互斥锁终止时: 1)如果其他服务/应用程序也引用了互斥锁,则下次获取互斥锁时,将引发异常。 2)如果它是唯一引用此互斥锁的程序,则os将为我妥善处理此操作,并且在下次获取时不会报告任何错误。
答案 0 :(得分:1)
readMutex.ReleaseMutex();
很可能在服务关闭时永远不会被调用
更进一步,Receive
一直阻塞直到收到消息为止,因此很有可能在服务关闭时超时,认为它已挂起,并杀死了进程而没有正常关闭。
这里有几种方法,
您最好在短超时时呼叫MessageQueue.Receive Method (TimeSpan)
,并相应地调整逻辑,这样(关闭时)接收有望在服务超时之前超时。 / p>
另一种方法是在线程或任务中运行它,并在关机时将其杀死,并确保您调用readMutex.ReleaseMutex()
现在无论如何您都有足够的信息,并且您应该能够以适合自己的方式解决此问题