服务重启后获取互斥锁时出现异常
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()
反正你现在已经掌握了足够的信息,你应该能够以适合你的方式解决这个问题
我正在用 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()
反正你现在已经掌握了足够的信息,你应该能够以适合你的方式解决这个问题