Comme le titre l'indique, je crée actuellement une application WPF et je dois détecter si une application est en cours d'exécution et faire quelque chose lorsqu'elle est fermée. La façon dont je pensais le faire est d'exécuter un thread séparé et de vérifier toutes les deux secondes si le processus est toujours en cours d'exécution, quelque chose comme ceci:
while(Process.GetProcessesByName(processName).Length != 0) { Thread.Sleep(2000); } //Do something
Serait-ce une bonne solution, c'est y a-t-il un autre moyen de faire cela?
Merci
3 Réponses :
Serait-ce une bonne solution?
Non, car cela gaspillerait un thread entier pour presque rien.
Mieux vaut utiliser un timer, dans une application WPF de préférence un DispatcherTimer:
var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(2) }; timer.Tick += async (s, e) => { if (Process.GetProcessesByName(processName).Length > 0) { await Task.Run(() => { // lengthy operation here which runs on a thread pool thread }); // udate UI here } }; timer.Start();
S'il y avait une longue opération à effectuer hors du thread de l'interface utilisateur, vous pouvez utiliser un gestionnaire d'événements asynchrone
Tick
qui attend uneTask
(qui s'exécuterait sur un thread de pool de threads en arrière-plan):var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(2) }; timer.Tick += (s, e) => { if (Process.GetProcessesByName(processName).Length > 0) { // ... } }; timer.Start();
Le Thread différent est nécessaire car l'utilisateur devrait être capable de faire des choses dans l'interface utilisateur pendant que cette opération s'exécute en arrière-plan, alors devrais-je utiliser une minuterie au lieu de Thread.
DispatcherTimer ne bloque pas l'interface utilisateur. S'il y a une longue opération à effectuer, utilisez un gestionnaire de ticks asynchrone. Voir la modification.
Je vais essayer la solution @ mm8, elle fonctionne sur un thread différent donc je pense que cela répond mieux à mes besoins, sinon je vais essayer la vôtre, merci beaucoup!
@ ÓscarFunesTrigo En fait, vous ne semblez pas avoir besoin d'un autre fil. Ou veuillez expliquer ce que le fil différent est censé faire exactement. S'il y a vraiment une longue opération qui devrait s'exécuter sur le thread d'interface utilisateur, alors async / await est la bonne approche. Nous ne traitons plus activement les threads aujourd'hui. Laissez le cadre gérer ces choses.
Fwiw. Task.run est un thread différent, si vous en avez besoin. Mais vous n'avez pas vraiment besoin d'une minuterie si vous utilisez async. Vous pouvez simplement faire une boucle en utilisant await task.delay.
@Andy Bien sûr, mais nous ne traitons pas explicitement de ce fait.
Voici la fonctionnalité dont j'ai besoin: je crée une application de type Steam. Un utilisateur peut cliquer sur `` Jouer '' sur l'un de ses jeux, et j'ai besoin de vérifier combien de temps l'utilisateur joue (c'est le problème du serveur), et donc je dois vérifier toutes les secondes ou 2 secondes si le jeu est toujours ouvert ( puisque c'est une autre application différente, non gérée par moi). Lorsqu'il détecte qu'il est fermé, il dit au serveur d'arrêter de compter le temps et de l'ajouter au jeu de l'utilisateur. Donc, pour le moment, je cherche juste un moyen efficace de vérifier si le processus est toujours en cours d'exécution, et si ce n'est pas le cas, dites-le au serveur
@ ÓscarFunesTrigo Ok, mais vérifier si le processus s'exécute ou non n'est pas une opération de longue haleine. Vous n'avez rien à faire de manière asynchrone ou dans un thread d'arrière-plan. Utilisez simplement un DispatcherTimer avec un gestionnaire d'événements Tick. Il est appelé à plusieurs reprises sans bloquer l'interface utilisateur.
Le code dans le gestionnaire d'événements Tick
bloque cependant.
@ mm8 Pour la durée de GetProcessesByName. Combien de temps est-ce?
Mais je pense que si je vérifie cette petite opération toutes les 2 secondes environ, cela ne sera-t-il pas remarqué à un moment donné par l'utilisateur? Je veux dire, cela bloque l'interface utilisateur, donc cela sera probablement remarqué à un moment donné, n'est-ce pas?
@ ÓscarFunesTrigo Cela prendra quelques millisecondes et se déroulera sans préavis. Vous pouvez même faire la vérification plusieurs fois par seconde. Essayez-le.
Vous pouvez utiliser un System.Timers.Timer
qui effectue la vérification toutes les x secondes:
public sealed partial class Window1 : Window, IDisposable { private readonly System.Timers.Timer _timer = new System.Timers.Timer(TimeSpan.FromSeconds(2).TotalMilliseconds); public Window1() { InitializeComponent(); _timer.Elapsed += _timer_Elapsed; _timer.Start(); } private void _timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { if (Process.GetProcessesByName("processName...").Length == 0) { _timer.Stop(); _timer.Dispose(); //do something... } } public void Dispose() { _timer.Dispose(); } }
Contrairement à l'événement Tick
de a DispatcherTimer
, l'événement Elapsed
d'un Timer
est toujours mis en file d'attente pour exécution sur un thread de pool de threads.
Depuis le docs :
Si un
System.Timers.Timer
est utilisé dans une application WPF, il convient de noter que leSystem.Timers.Timer
s'exécute sur un thread différent de celui de l'utilisateur interface (UI) thread ... Les raisons d'utiliser unDispatcherTimer
par opposition à unSystem.Timers.Timer
sont que leDispatcherTimer
s'exécute sur le le même thread que leDispatcher
et unDispatcherPriority
peuvent être définis sur leDispatcherTimer
.
Je pense que je vais essayer, je pense que c'est plus ce que je recherche, car il fonctionne sur un thread différent. Le minuteur démarre-t-il dès qu'une valeur lui est attribuée? Je ne vois pas de _timer.Start () ou quelque chose comme ça
@ ÓscarFunesTrigo: Non, désolé, vous devez le démarrer en appelant Start ()
selon ma modification.
Aah, je vois. Je ne peux pas essayer jusqu'à ce que je rentre à la maison, mais merci beaucoup! Je commenterai les résultats
Puisque vous avez déjà affaire à des processus, je suggérerais simplement de l'utiliser directement pour déterminer s'il s'est arrêté. Vous pouvez utiliser le Quitté gestionnaire d'événements pour votre code. Ainsi, par exemple: Cela appellera foreach (var process in Process.GetProcessesByName(processName))
{
process.Exited += new EventHandler(DoSomething);
}
â¦
public void DoSomething(object sender, System.EventArgs e)
{
// do something
}
DoSomething
lorsque le processus portant ce nom se termine.
Mec, tu es une bouée de sauvetage, maintenant je n'ai plus besoin de vérifier tout le temps, merci!
Vous pouvez utiliser une minuterie.