12
votes

Attendre le système.threading.Timer rappels à compléter avant de quitter le programme

J'ai une liste . Chaque minuterie déclenche à un intervalle configurable (10 minutes par défaut). Tout appeler la même méthode de rappel (avec un paramètre différent). La méthode de rappel peut prendre plusieurs secondes pour compléter son travail.

Lorsque le programme se termine, il semble que l'exécution de la méthode de rappel est immédiatement arrêtée (je le vois correctement?).

Comment puis-je attendre élégamment toutes les méthodes de rappel d'exécution à la fin avant de quitter le programme?


0 commentaires

4 Réponses :


-2
votes

Il n'est probablement pas possible d'attendre la sortie dans la demande de console.

Pour les formulaires Windows Application:

Vous pouvez créer une variable de compteur de rappel en marche statique qui sera augmentée chaque fois que le rappel est démarré et diminué à la sortie. Bien sûr, vous devez utiliser la serrure lorsque vous le faites.

Et puis vous pouvez vérifier l'événement correspondant et que vous attendez de devenir 0 ou d'annuler la sortie.


2 commentaires

En effet, c'est ;-) msdn.microsoft.com/en-gb/library/...


La solution de Tomek fonctionne bien dans une application de console. Votre solution fonctionnerait également dans une console. L'application devrait interroger le compteur en attente d'atteindre 0 avant la sortie principale.



1
votes

Vous pouvez utiliser ManualResetvents pour bloquer le fil principal jusqu'à ce que des opérations en attente soient terminées.

Par exemple, si vous souhaitez tous les minuteries em> pour exécuter au moins une fois que vous pourriez avoir un System.threading.ManualResetEvent [] code> tableau avec l'état initial défini sur Non -signalled p>

Donc quelque part dans votre code, vous auriez la configuration de votre minuterie et il est associé à l'initialisation de Waihandle. P>

_waithandles[0] = new ManualResetEvent(true); // initial state set to non blocking. 

private void MyExecute() 
{
    _waithandles[0].Reset(); // set this waithandle to block.. 

    // do all my logic then when done signal the manual reset event 
    _waithandles[0].Set(); 
}


0 commentaires

17
votes

Vous pouvez disposer de toutes les minuteries avec le paramètre WAITHANDLER. Ce gestionnaire ne sera signalé que lorsque la méthode de rappel est terminée (comme spécification indique: "La minuterie n'est pas disposée tant que tous les rappels en file d'attente actuellement terminés.")

void WaitUntilCompleted(List<Timer> myTimers)
{
    List<WaitHandle> waitHnd = new List<WaitHandle>();
    foreach (var timer in myTimers)
    {
        WaitHandle h = new AutoResetEvent(false);
        if(!timer.Dispose(h)) throw new Exception("Timer already disposed.");
        waitHnd.Add(h);
    }
    WaitHandle.WaitAll(waitHnd.ToArray());
}


1 commentaires

Je viens de tester cela et @Peter a raison: vous pouvez avoir une impasse si vous disposez de plusieurs fois. Sa réponse est la bonne.



6
votes

La réponse acceptée de Tomek est belle, mais incomplète. Si la fonction d'élimination renvoie False, cela signifie qu'il n'est pas nécessaire d'attendre l'achèvement, car le thread est déjà terminé. Si vous essayez d'attendre d'attendre sur un siplacement dans un tel cas, WAITELLA ne reviendra jamais, vous vous avez donc créé une fonction qui gèle arbitrairement votre application / thread.

Voici comment il devrait regarder: xxx


2 commentaires

En désaccord, le jeton retournera faux que si appelé plus d'une fois sur la minuterie. Le fait que le rappel de la minuterie ait fini n'affecte pas l'élimination de la valeur de retour.


Vous devez vous assurer que le rappel n'a pas déjà été licencié, s'il s'agit d'une minuterie unique, vous finirez par attendre pour toujours.