Rozważ aplikację konsolową, która uruchamia niektóre usługi w osobnym wątku. Wszystko, co musi zrobić, to poczekać, aż użytkownik naciśnie Ctrl + C, aby go wyłączyć.
Która z poniższych opcji jest lepszym sposobem na zrobienie tego?
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
}
Lub to, używając 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
źródło
źródło
bool
nie jest zadeklarowane jakovolatile
, istnieje wyraźna możliwość, że kolejne odczyty_quitFlag
wwhile
pętli zostaną zoptymalizowane, co prowadzi do nieskończonej pętli.Alternatywnie prostszym rozwiązaniem jest po prostu:
źródło
Możesz to zrobić (i usunąć
CancelKeyPress
moduł obsługi zdarzeń):Nie jestem pewien, czy to jest lepsze, ale nie podoba mi się pomysł wywoływania
Thread.Sleep
pętli. Myślę, że blokowanie danych wejściowych użytkownika jest czystsze.źródło
Wolę korzystać z Application.Run
z dokumentów:
źródło
Wygląda na to, że utrudniasz to, niż potrzebujesz. Dlaczego nie tylko
Join
wątek po zasygnalizowaniu jego zatrzymania?źródło
Możliwe jest również zablokowanie wątku / programu na podstawie tokenu anulowania.
WaitHandle jest sygnalizowany, gdy token jest anulowany.
Widziałem tę technikę używaną przez Microsoft.Azure.WebJobs.JobHost, gdzie token pochodzi ze źródła tokenu anulowania WebJobsShutdownWatcher (obserwator plików, który kończy zadanie).
Daje to pewną kontrolę nad tym, kiedy program może się zakończyć.
źródło
CTL+C
ponieważ wykonuje długotrwałą operację lub jest demonem, który powinien również z wdziękiem zamknąć swoje wątki robocze. Zrobiłbyś to za pomocą CancelToken, więc ta odpowiedź korzysta zWaitHandle
tego, który już istniałby, zamiast tworzyć nowy.Z dwóch pierwszy jest lepszy
ponieważ w drugim wątek budzi się co jedną milisekundę i zostaje zamieniony na przerwanie systemu operacyjnego, co jest drogie
źródło
Console
metod, jeśli nie masz podłączonej konsoli (bo np. Program jest uruchamiany przez usługę)Powinieneś to zrobić tak, jak gdybyś programował usługę Windows. Nigdy nie użyłbyś instrukcji while zamiast tego użyłbyś delegata. WaitOne () jest zwykle używana podczas oczekiwania na usunięcie wątków - Thread.Sleep () - nie jest zalecane - Czy myślałeś o użyciu System.Timers.Timer przy użyciu tego zdarzenia do sprawdzenia zdarzenia zamknięcia?
źródło