Рассмотрим консольное приложение, которое запускает некоторые службы в отдельном потоке. Все, что ему нужно сделать, это дождаться, пока пользователь нажмет Ctrl + C, чтобы выключить его.
Что из следующего является лучшим способом сделать это?
static ManualResetEvent _quitEvent = new ManualResetEvent(false);
static void Main() {
Console.CancelKeyPress += (sender, eArgs) => {
_quitEvent.Set();
eArgs.Cancel = true;
};
// kick off asynchronous stuff
_quitEvent.WaitOne();
// cleanup/shutdown and quit
}
Или так, используя Thread.Sleep (1):
static bool _quitFlag = false;
static void Main() {
Console.CancelKeyPress += delegate {
_quitFlag = true;
};
// kick off asynchronous stuff
while (!_quitFlag) {
Thread.Sleep(1);
}
// cleanup/shutdown and quit
}
c#
multithreading
sleep
manualresetevent
intoOrbit
источник
источник
bool
не объявлен какvolatile
, существует определенная вероятность того, что последующие чтения_quitFlag
вwhile
цикле будут оптимизированы, что приведет к бесконечному циклу.В качестве альтернативы более простое решение:
источник
Вы можете сделать это (и удалить
CancelKeyPress
обработчик событий):Не уверен, что так лучше, но мне не нравится идея вызова
Thread.Sleep
цикла ... Я думаю, что проще заблокировать ввод пользователя.источник
Я предпочитаю использовать Application.Run
из документов:
источник
Похоже, ты делаешь это сложнее, чем нужно. Почему не просто
Join
нить после того, как вы подали ей сигнал остановиться?источник
Также возможно заблокировать поток / программу на основе токена отмены.
WaitHandle получает сигнал, когда токен отменяется.
Я видел этот метод, используемый Microsoft.Azure.WebJobs.JobHost, где токен поступает из источника токена отмены WebJobsShutdownWatcher (наблюдателя за файлами, который завершает задание).
Это дает некоторый контроль над тем, когда программа может закончиться.
источник
CTL+C
потому что оно выполняет длительную операцию или является демоном, который также должен корректно завершать свои рабочие потоки. Вы бы сделали это с помощью CancelToken, и поэтому этот ответ используетWaitHandle
уже существующий, а не создает новый.Из двух первый лучше
потому что во втором поток просыпается каждую миллисекунду и превращается в прерывание ОС, что дорого
источник
Console
методов, если у вас нет подключенной консоли (потому что, например, программа запускается службой)Вы должны сделать это так же, как если бы вы программировали службу Windows. Вы бы никогда не использовали оператор while, вместо этого вы использовали бы делегат. WaitOne () обычно используется при ожидании удаления потоков - Thread.Sleep () - не рекомендуется. Думали ли вы об использовании System.Timers.Timer, используя это событие для проверки события завершения работы?
источник