У меня есть процесс, который выполняется в собственном потоке и может быть запущен / остановлен без блокировки. В конечном итоге это перейдет в службу Windows, но пока я настраиваю это в консольном приложении, пока оно не будет полностью реализовано.
После вызова Start () я хочу, чтобы основной поток программы блокировался до тех пор, пока не будет нажата Ctrl-C. Я знаю, что это сработает:
public static void Main(string[] args)
{
bool keepGoing = true;
var service = new Service();
System.Console.TreatControlCAsInput = false;
System.Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e)
{
e.Cancel = true;
service.Stop();
keepGoing = false; // Break the while loop below
};
service.Start();
while( keepGoing )
{
Thread.Sleep(100); // 100 is arbitrary
}
}
Однако меня надоедают флаг и произвольное значение сна. Я знаю, что стоимость ЦП практически равна нулю в цикле while, но я бы предпочел иметь «жесткий» блок, который освобождается, как только будет выполнен обработчик Ctrl-C.Я разработал следующее, используя семафор для блокировки, пока не будет выполнен анонимный обработчик Ctrl-C:
public static void Main(string[] args)
{
var service = new Service();
var s = new Semaphore(1, 1);
System.Console.TreatControlCAsInput = false;
System.Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e)
{
e.Cancel = true;
service.Stop();
s.Release(); // This will allow the program to conclude below
};
service.Start();
s.WaitOne(); // This will not block
s.WaitOne(); // This will block w/o CPU usage until the sempahore is released
}
Это плохой дизайн? Это излишество? Это опасно?
РЕДАКТИРОВАТЬ:
Я также подключаю AppDomain.CurrentDomain.UnhandledException следующим образом:
AppDomain.CurrentDomain.UnhandledException += delegate {
service.Stop();
s.Release();
};
ИЗМЕНИТЬ 2-е:
Я должен отметить, что очень важно, чтобы Stop ()
метод вызывается при выходе. @Adam Ralph имеет совершенно хороший шаблон для гибридной консоли / сервиса, но у него не было этой информации при ответе на вопрос.