Interrompre un Thread en sommeil
Est-il possible d'Interrompre un thread en sommeil? Si j'ai un code similaire à cela.
while(true){
if(DateTime.Now.Subtract(_lastExecuteTime).TotalHours > 1){
DoWork();
_lastExecuteTime = DateTime.Now();
continue;
}
Thread.Sleep(10000) //Sleep 10 seconds
if(somethingIndicatingQuit){
break;
}
}
Je suis désireux d'exécuter DoWork() toutes les heures. Donc, j'aimerais dormir un peu plus longtemps que 10 secondes. Dire vérifier toutes les 10 minutes. Cependant, si la valeur de mon sommeil à 10 minutes, et j'ai envie de tuer cette tâche en arrière-plan, je dois attendre pour le sommeil pour reprendre.
Mon code est à l'aide d'un Filetage.ManualResetEvent pour arrêter le travail de fond, mais mon problème est avec le ThreadSleep code. Je peux poster plus de code si nécessaire.
OK, je vais ajouter un peu plus de code complet ici car je pense que cela va répondre à certaines questions.
private readonly ManualResetEvent _shutdownEvent = new ManualResetEvent(false);
private readonly ManualResetEvent _pauseEvent = new ManualResetEvent(true);
private Thread _backGroundWorkerThread;
//This starts our work
public void Start() {
_backGroundWorkerThread = new Thread(ExecuteWorker) {IsBackground = true, Name = WorkerName + "_Thread"};
_shutdownEvent.Reset();
_backGroundWorkerThread.Start();
}
internal void Stop() {
//Signal the shutdown event
_shutdownEvent.Set();
//Make sure to resume any paused threads
_pauseEvent.Set();
//Wait for the thread to exit
_backGroundWorkerThread.Join();
}
private void ExecuteWorker() {
while (true) {
_pauseEvent.WaitOne(Timeout.Infinite);
//This kills our process
if (_shutdownEvent.WaitOne(0)) {
break;
}
if (!_worker.IsReadyToExecute) {
//sleep 5 seconds before checking again. If we go any longer we keep our service from shutting down when it needs to.
Thread.Sleep(5000);
continue;
}
DoWork();
}
}
Mon problème est ici,
_backGroundWorkerThread.Join();
Ce attend pour le Thread.Dormir dans le ExecuteWorker() qui est en cours d'exécution dans mon thread d'arrière-plan.
J'ai posté plus de code. La classe de ce code est un enfant d'un parent de la classe qui gère un nombre infini de ces. Les contrôles parent le Démarrage, l'Arrêt, la Suspension et la reprise de ces classes enfant et le travail qu'ils font. Ce n'est pas une simple question de Start et de Stop qui doit être pris en charge.
qu'est-ce que
_worker
ici?Juste une instance d'une classe qui a la planification de la logique. C'est la méthode, IsReadyToExecute renvoie une valeur booléenne. Le _worker n'est pas germane à cette question.
OriginalL'auteur Jeff Reddy | 2011-09-16
Vous devez vous connecter pour publier un commentaire.
Au lieu d'utiliser
Thread.Sleep
utilisationManualResetEvent.WaitOne
.Où
terminate
est unManualResetEvent
1 que vous pouvezSet
à la demande de résiliation de la boucle.Mise à jour:
Je viens de remarquer que vous avez dit que vous utilisez déjà
ManualResetEvent
de résilier le travail de fond (je suis en supposant que c'est dansDoWork
). Est-il une raison pourquoi vous ne pouvez pas utiliser le même MRE? Si cela n'est pas possible, il ne devrait certainement pas être un problème en utilisant une autre.Mise à jour 2:
Ouais, donc au lieu de
Thread.Sleep(5000)
dansExecuteWorker
ne_shutdownEvent.WaitOne(5000)
à la place. Il ressemble à la suivante.1Il y a aussi un
ManualResetEventSlim
classe .NET 4.0.Nice, vous êtes le premier que j'ai croisé ici 🙂
OriginalL'auteur Brian Gideon
Au lieu d'utiliser
Thread.Sleep
, vous pouvez utiliserMonitor.Wait
avec un délai d'attente - et puis, vous pouvez utiliserMonitor.Pulse
à partir d'un autre thread pour le réveiller.N'oubliez pas que vous aurez besoin de se verrouiller sur le moniteur avant d'appeler soit
Wait
ouPulse
:Si Jon Skeet vous donne une réponse et ne pas travail, vous êtes à la mise en œuvre de sa réponse erronée 🙂
Aussi, Jon, vous avez remplacé ma boucle sans fin --> while(true) avec serrure(moniteur). Pas sûr de ce que cela fait pour moi. Aussi, À Surveiller.Pulse(); donnez-moi une exception de la Méthode 'Impulsion' a 1 paramètre(s) butis invoqué avec 0 argument(s).
C'est une réponse très - résolu mon problème et c'était le meilleur exemple de Moniteur que j'ai trouvé. Un peu de demande de mise à jour de votre réponse à préciser ce qu'est l'
monitor
variable est? Peut-être évident pour certains, mais j'ai dû regarder un peu autour. Merci!En effet, une grande réponse - ce lien ci-dessous a également été très utile: albahari.com/threading/...
OriginalL'auteur Jon Skeet
Vous pouvez utiliser Thead.Interruption de réveiller un thread en sommeil. Cela va entraîner un
ThreadInteruptedException
sur le thread bloqué, donc ce n'est pas la plus élégante ou approche efficace.Vous devez également être fatigué qu'interrompre un thread dans cette voie est dangereuse. Il ne fournit pas de contrôle sur le point où le fil est abandonné, et par conséquent ne doit pas être utilisé sans un examen attentif des conséquences. Comme mentionné dans d'autres réponses déjà, il est de loin préférable d'utiliser fondée sur le signal, les techniques de contrôle lorsque le thread se termine d'une manière contrôlée.
Dangereux dans quel sens? Il jette un
ThreadInteruptedException
sur le blocage du thread. Peut-être que vous pourriez préciser? Je suppose que tu veux dire, si c'est bloquant pour une raison autre que le sommeil?Dangereux parce que vous n'avez aucun moyen de connaître l'état de la thread a été interrompu. Le thread ne pas être interrompue à "la sécurité des points" - il est interrompu partout où il se trouve. Cela pourrait être un point dans le temps où l'état de l'application n'est pas défini ou incorrectes, ou tout simplement faux.
Juste point, je vais ajouter une note à ce sujet pour référence. Je suis conscient qu'il existe de meilleures alternatives, juste ne veut pas répéter les mêmes réponses.
Thread.Interrupt
coffre-fort. Il estThread.Abort
qui n'est pas sûr.Interrupt
seulement des causes qui BCL en attente des appels (commeJoin
,Sleep
, etc.) pour revenir immédiatement. À moins que votre code est défectueux l'ThreadInterruptException
doit get injecté à la sécurité des points et vous avez le plein contrôle. Juste faire attention à l'emplacement du blocage des appels, si vous décidez d'utiliserInterrupt
. Encore une fois, l'interruption et l'abandon de threads sont deux choses très différentes!OriginalL'auteur TheCodeKing
Ne pouvez-vous pas juste envelopper de votre Fil.Dormir partie dans une boucle pour qu'elle boucle de 60 fois, puis fait de l'autre? Bien sûr, tout cela n'est de faire un compromis entre une simple si(somethingIndicatingQuit) rapport à l'DateTIme si vérifier, mais en supposant que vous êtes peut-être vrai code n'quelque chose de plus cher, avoir un deuxième boucle pourrait offrir quelques petites CPU d'épargne.
OriginalL'auteur Tod
Si vous voulez DoWork() toutes les heures, pourquoi ne pas calculer le nombre de ms jusqu'à ce que l'heure suivante est en attente de ce moment-là? Pour annuler l'arrêt, vous pouvez soit utiliser un waitable synchro classe, comme le moniteur, comme suggéré par @Jon Skeet, ou il suffit de mettre un drapeau dans le thread qui lui dit de sortir après le sommeil au lieu de DoWork() et tout simplement l'oublier -, soit le fil se tuer lui-même lorsque le temps est écoulé, ou votre système d'exploitation va le tuer sur l'app proche, selon la première éventualité.
Rgds,
Martin
OriginalL'auteur Martin James
pourquoi ne pas utiliser un BlockingCollection? Je le vois comme un beaucoup plus élégant que l'on a accepté la réponse. j'ai aussi ne pense pas qu'il y est beaucoup de frais généraux par rapport à l'écran.
voici comment le faire:
initialiser un BlockingCollection en tant que membre:
place de
ce faire
pour le réveiller, vous pouvez utiliser ce code
OriginalL'auteur schmendrick