一般来说,你can't保证线程退出时释放信号量。您可以编写 try/finally 块和关键终结器,但如果程序异常终止,这些并不总是有效。而且,与互斥体不同,如果线程在仍持有信号量时退出,则不会通知其他线程。
原因是,Windows 信号量对象.NET Semaphore 对象所基于的,不会跟踪哪些线程已获取它,因此不能抛出类似于AbandonedMutexException
.
也就是说,你can当用户关闭窗口时收到通知。您需要设置一个控制处理程序来侦听特定事件。您调用 Windows API 函数设置ConsoleCtrlHandler,向其传递一个处理您感兴趣的事件的回调函数(委托)。我这样做已经有一段时间了,但总的来说。
为以下内容创建一个托管原型SetConsoleCtrlHandler
函数和回调:
/// <summary>
/// Control signals received by the console control handler.
/// </summary>
public enum ConsoleControlEventType: int
{
/// <summary>
/// A CTRL+C signal was received, either from keyboard input or from a
/// signal generated by the GenerateConsoleCtrlEvent function.
/// </summary>
CtrlC = 0,
/// <summary>
/// A CTRL+BREAK signal was received, either from keyboard input or from
/// a signal generated by GenerateConsoleCtrlEvent.
/// </summary>
CtrlBreak = 1,
/// <summary>
/// A signal that the system sends to all processes attached to a console
/// when the user closes the console (either by clicking Close on the console
/// window's window menu, or by clicking the End Task button command from
/// Task Manager).
/// </summary>
CtrlClose = 2,
// 3 and 4 are reserved, per WinCon.h
/// <summary>
/// A signal that the system sends to all console processes when a user is logging off.
/// </summary>
CtrlLogoff = 5,
/// <summary>
/// A signal that the system sends to all console processes when the system is shutting down.
/// </summary>
CtrlShutdown = 6
}
/// <summary>
/// Control event handler delegate.
/// </summary>
/// <param name="CtrlType">Control event type.</param>
/// <returns>Return true to cancel the control event. A return value of false
/// will terminate the application and send the event to the next control
/// handler.</returns>
public delegate bool ConsoleCtrlHandlerDelegate(ConsoleControlEventType CtrlType);
[DllImport("kernel32.dll", SetLastError=true)]
public static extern bool SetConsoleCtrlHandler(
ConsoleCtrlHandlerDelegate HandlerRoutine,
bool Add);
现在,创建您的处理程序方法:
private static bool ConsoleCtrlHandler(ConsoleControlEventType CtrlType)
{
switch (CtrlType)
{
case CtrlClose:
// handle it here
break;
case CtrlBreak:
// handle it here
break;
}
// returning false ends up calling the next handler
// returning true will prevent further handlers from being called.
return false;
}
最后,在初始化期间您要设置控制处理程序:
SetConsoleCtrlHandler(ConsoleControlHandler);
现在,当用户关闭窗口时,将调用您的控制处理程序。这将允许您释放信号量或进行其他清理。
您可能对我的感兴趣控制台DotNet包。我写了三篇关于这些内容的文章,其中最后两篇仍然可以在 DevSource 上找到。我不知道第一个发生了什么。
- .NET 中的控制台输入
- 在 .NET 中使用控制台屏幕缓冲区