У меня есть процесс, который работает в своем собственном потоке и может быть запущен / остановлен без блокировки.Это в конечном итоге перейдет в службу 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 стоимость процессора практически равна 0, но я бы предпочел иметь «жесткий» блок, который освобождается, как только обработчик 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 очень хороший образец для гибридной консоли / службы, но он не имел этой информации при ответе на вопрос.