Considérons une application console qui démarre certains services dans un thread séparé. Il suffit d’attendre que l’utilisateur appuie sur Ctrl + C pour le fermer.
Quel est le meilleur moyen de procéder?
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 ceci, en utilisant 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
}
vous voulez toujours éviter d'utiliser des boucles while, surtout lorsque vous forcez le code à revérifier les variables. Cela gaspille les ressources du processeur et ralentit votre programme.
Je dirais certainement le premier.
Alternativement, une solution plus simple est simplement:
Console.ReadLine();
Vous pouvez le faire (et supprimer le gestionnaire d'événements CancelKeyPress
):
while(!_quitFlag)
{
var keyInfo = Console.ReadKey();
_quitFlag = keyInfo.Key == ConsoleKey.C
&& keyInfo.Modifiers == ConsoleModifiers.Control;
}
Pas sûr que ce soit mieux, mais je n'aime pas l'idée d'appeler Thread.Sleep
dans une boucle.
Je préfère utiliser le Application.Run
static void Main(string[] args) {
//Do your stuff here
System.Windows.Forms.Application.Run();
//Cleanup/Before Quit
}
des docs:
Commence à exécuter une boucle de message d'application standard sur le thread actuel, sans formulaire.
On dirait que vous rendez la tâche plus difficile que nécessaire. Pourquoi ne pas simplement Join
le thread après l’avoir signalé son arrêt?
class Program
{
static void Main(string[] args)
{
Worker worker = new Worker();
Thread t = new Thread(worker.DoWork);
t.IsBackground = true;
t.Start();
while (true)
{
var keyInfo = Console.ReadKey();
if (keyInfo.Key == ConsoleKey.C && keyInfo.Modifiers == ConsoleModifiers.Control)
{
worker.KeepGoing = false;
break;
}
}
t.Join();
}
}
class Worker
{
public bool KeepGoing { get; set; }
public Worker()
{
KeepGoing = true;
}
public void DoWork()
{
while (KeepGoing)
{
Console.WriteLine("Ding");
Thread.Sleep(200);
}
}
}
Des deux premiers c'est mieux
_quitEvent.WaitOne();
parce que dans le second le thread se réveille chaque milliseconde sera transformé en interruption du système d'exploitation qui est coûteux
Il est également possible de bloquer le thread/programme en fonction d'un jeton d'annulation.
token.WaitHandle.WaitOne();
WaitHandle est signalé lorsque le jeton est annulé.
J'ai vu cette technique utilisée par Microsoft.Azure.WebJobs.JobHost, où le jeton provient d'une source de jeton d'annulation de WebJobsShutdownWatcher (un observateur de fichier qui termine le travail).
Cela donne un certain contrôle sur la fin du programme.
Vous devriez le faire comme si vous programmiez un service Windows. Vous n'utiliseriez jamais une instruction while, mais un délégué. WaitOne () est généralement utilisé en attendant que les threads soient mis au rebut. Thread.Sleep () n'est pas conseillé. Avez-vous pensé à utiliser System.Timers.Timer en utilisant cet événement pour rechercher un événement de fermeture?