0
votes

Dois-je utiliser Thread.Sleep () pour vérifier si un processus est toujours en cours d'exécution?

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


1 commentaires

Vous pouvez utiliser une minuterie.


3 Réponses :


3
votes

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 une Task (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();

12 commentaires

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.



0
votes

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 le System.Timers.Timer s'exécute sur un thread différent de celui de l'utilisateur interface (UI) thread ... Les raisons d'utiliser un DispatcherTimer par opposition à un System.Timers.Timer sont que le DispatcherTimer s'exécute sur le le même thread que le Dispatcher et un DispatcherPriority peuvent être définis sur le DispatcherTimer .


3 commentaires

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



1
votes

1 commentaires

Mec, tu es une bouée de sauvetage, maintenant je n'ai plus besoin de vérifier tout le temps, merci!