Considere um aplicativo de console que inicializa alguns serviços em um thread separado. Tudo o que precisa fazer é esperar que o usuário pressione Ctrl + C para desligá-lo.
Qual das alternativas a seguir é a melhor maneira de fazer isso?
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
}
Ou isso, usando 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
fonte
fonte
bool
não é declarado comovolatile
, há a possibilidade definitiva de que as leituras subsequentes para_quitFlag
nowhile
loop sejam otimizadas, levando a um loop infinito.Alternativamente, uma solução mais simples é apenas:
fonte
Você pode fazer isso (e remover o
CancelKeyPress
manipulador de eventos):Não tenho certeza se isso é melhor, mas não gosto da ideia de chamar
Thread.Sleep
em um loop .. Acho que é mais limpo bloquear a entrada do usuário.fonte
Eu prefiro usar o Application.Run
dos documentos:
fonte
Parece que você está tornando tudo mais difícil do que o necessário. Por que não apenas
Join
o tópico depois que você sinalizou para parar?fonte
Também é possível bloquear o thread / programa com base em um token de cancelamento.
WaitHandle é sinalizado quando o token é cancelado.
Eu vi essa técnica usada pelo Microsoft.Azure.WebJobs.JobHost, onde o token vem de uma fonte de token de cancelamento do WebJobsShutdownWatcher (um inspetor de arquivo que encerra o trabalho).
Isso dá algum controle sobre quando o programa pode terminar.
fonte
CTL+C
porque está executando uma operação de longa duração, ou é um daemon, que também deve desligar normalmente seus threads de trabalho. Você faria isso com um CancelToken e, portanto, essa resposta tira proveito de umWaitHandle
que já existe, em vez de criar um novo.Dos dois primeiros um é melhor
porque no segundo a thread acorda a cada milissegundo e vai para a interrupção do sistema operacional que é cara
fonte
Console
métodos se você não tiver um console conectado (porque, por exemplo, o programa é iniciado por um serviço)Você deve fazer isso como faria se estivesse programando um serviço do Windows. Você nunca usaria uma instrução while, em vez de usar um delegado. WaitOne () é geralmente usado enquanto espera os threads descartar - Thread.Sleep () - não é aconselhável - Você já pensou em usar System.Timers.Timer usando esse evento para verificar o evento de desligamento?
fonte