Pertimbangkan aplikasi Konsol yang memulai beberapa layanan di utas terpisah. Yang perlu dilakukan hanyalah menunggu pengguna menekan Ctrl + C untuk mematikannya.
Manakah dari berikut ini yang merupakan cara terbaik untuk melakukan ini?
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
}
Atau ini, menggunakan 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
sumber
sumber
bool
tidak dideklarasikan sebagaivolatile
, ada kemungkinan pasti bahwa pembacaan berikutnya ke_quitFlag
dalamwhile
loop akan dioptimalkan, yang mengarah ke loop tak terbatas.Alternatifnya, solusi yang lebih sederhana hanyalah:
sumber
Anda bisa melakukannya (dan menghapus
CancelKeyPress
event handler):Tidak yakin apakah itu lebih baik, tetapi saya tidak suka gagasan memanggil
Thread.Sleep
dalam satu lingkaran .. Saya pikir itu lebih bersih untuk memblokir masukan pengguna.sumber
Saya lebih suka menggunakan Application.Run
dari dokumen:
sumber
Sepertinya Anda membuatnya lebih sulit dari yang Anda butuhkan. Mengapa tidak hanya
Join
utas setelah Anda memberi isyarat untuk berhenti?sumber
Ini juga memungkinkan untuk memblokir utas / program berdasarkan token pembatalan.
WaitHandle diberi tanda ketika token dibatalkan.
Saya telah melihat teknik ini digunakan oleh Microsoft.Azure.WebJobs.JobHost, di mana token itu berasal dari sumber token pembatalan WebJobsShutdownWatcher (pengamat file yang mengakhiri pekerjaan).
Ini memberi beberapa kendali atas kapan program bisa berakhir.
sumber
CTL+C
karena menjalankan operasi yang berjalan lama, atau merupakan daemon, yang juga harus mematikan thread pekerja dengan baik. Anda akan melakukannya dengan CancelToken dan jawaban ini memanfaatkanWaitHandle
yang sudah ada, daripada membuat yang baru.Dari dua yang pertama lebih baik
karena di thread kedua thread yang aktif setiap satu milidetik akan dialihkan ke interupsi OS yang mahal
sumber
Console
metode jika Anda tidak memiliki konsol yang terpasang (karena, misalnya, program dimulai oleh layanan)Anda harus melakukannya seperti yang Anda lakukan jika Anda memprogram layanan windows. Anda tidak akan pernah menggunakan pernyataan while sebagai gantinya Anda akan menggunakan delegasi. WaitOne () umumnya digunakan sambil menunggu utas dibuang - Thread.Sleep () - tidak disarankan - Pernahkah Anda berpikir untuk menggunakan System.Timers.Timer menggunakan acara itu untuk memeriksa acara mematikan?
sumber