В общем, вы не можете гарантировать, что поток выпускает семафор при выходе из потока.Вы можете написать блоки try / finally и критические финализаторы, но они не всегда будут работать, если программа завершится ненормально.И, в отличие от мьютексов, другие потоки не будут уведомлены, если поток завершается, пока он все еще содержит семафор.
Причина в том, что объект семафора Windows , на котором основан объект .NET Semaphore, не отслеживает, какие потоки его получили, и поэтому не может выдатьисключение аналогично AbandonedMutexException
.
Тем не менее, вы можете быть уведомленным, когда пользователь закроет окно.Вам необходимо установить обработчик элемента управления для прослушивания определенных событий.Вы вызываете функцию Windows API SetConsoleCtrlHandler , передавая ей функцию обратного вызова (делегат), которая обрабатывает интересующие вас события. С тех пор, как я это сделал, прошло довольно много времени.
Создайте управляемый прототип для функции 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);
Ваш обработчик управления теперь будет вызываться, когда пользователь закрывает окно.Это позволит вам освободить семафор или выполнить другую очистку.
Возможно, вас заинтересует мой пакет ConsoleDotNet .Я написал три статьи об этом материале, последние две из которых все еще доступны на DevSource.Я не знаю, что случилось с первым.