Comment est-ce que j'arrête gracieusement un System.Threading.Timer?
J'ai un Windows Service implémenté en C# qui doit faire un peu de travail chaque tellement souvent. J'ai mis en place ce à l'aide d'un System.Threading.Timer
avec une méthode de rappel qui est responsable de la planification de la fonction de rappel. J'ai de la difficulté avec élégance l'arrêt (c'est à dire l'élimination) de la minuterie. Voici quelques simplifié de code que vous pouvez exécuter dans une application console qui illustre mon problème:
const int tickInterval = 1000; //one second
timer = new Timer( state => {
//simulate some work that takes ten seconds
Thread.Sleep( tickInterval * 10 );
//when the work is done, schedule the next callback in one second
timer.Change( tickInterval, Timeout.Infinite );
},
null,
tickInterval, //first callback in one second
Timeout.Infinite );
//simulate the Windows Service happily running for a while before the user tells it to stop
Thread.Sleep( tickInterval * 3 );
//try to gracefully dispose the timer while a callback is in progress
var waitHandle = new ManualResetEvent( false );
timer.Dispose( waitHandle );
waitHandle.WaitOne();
Le problème est que je reçois un ObjectDisposedException
de timer.Change
sur le rappel de filetage waitHandle.WaitOne
est bloquant. Ce que je fais mal?
La documentation pour la Dispose
surcharge je suis en utilisant dit:
La minuterie n'est pas disposé jusqu'à ce que tous actuellement en file d'attente des rappels avez terminé.
Edit: Il semble que cette déclaration de la documentation peut être incorrect. Quelqu'un peut-il vérifier?
Je sais que je pourrais contourner le problème en ajoutant de la signalisation entre le rappel et à l'élimination code Henk Holterman suggéré ci-dessous, mais je ne veux pas le faire, sauf si absolument nécessaire.
source d'informationauteur William Gross
Vous devez vous connecter pour publier un commentaire.
Avec ce code
il est presque certain que vous permettra de Disposer de la minuterie pendant qu'il dort.
Vous devrez sauvegarder le code après le Sommeil() pour détecter un Disposé à rebours. Puisqu'il n'est pas IsDisposed bien un moyen rapide et sale
static bool stopping = false;
pourrait faire l'affaire.Solution Possible pour la protection de la méthode de rappel de travailler sur un disposé à rebours:
https://stackoverflow.com/a/15902261/193178
Comme décrit dans "la Programmation Simultanée sur Windows":
Créer un mannequin de classe InvalidWaitHandle, héritant de WaitHandle:
Par conséquent, vous pouvez Disposer d'un Système.Le filetage.Timer correctement comme ceci:
Vous n'avez pas besoin de disposer de la minuterie pour l'arrêter. Vous pouvez appeler
Timer.Stop()
ou un ensembleTimer.Enabled
àfalse
soit de ce qui sera l'arrêt de la minuterie de course.