J’écris une application Windows qui exécute une séquence d’actions IO numériques à plusieurs resockets.
Cette séquence d’actions commence lorsque l’utilisateur clique sur un bouton “START”, et cela est fait par un agent d’arrière-plan dans backgroundWorker1_DoWork ().
Cependant, il y a des occasions où je reçois le message d’erreur “Ce backgroundworker est actuellement occupé …”.
Je pense à implémenter ce qui suit dans le code, en utilisant une boucle while pour “tuer” le travailleur d’arrière-plan avant de commencer une autre séquence d’action:
if (backgroundWorker1.IsBusy == true) { backgroundWorker1.CancelAsync(); while (backgroundWorker1.IsBusy == true) { backgroundWorker1.CancelAsync(); } backgroundWorker1.Dispose(); } backgroundWorker1.RunWorkerAsync();
Je pense que ma principale préoccupation est la suivante: le backgroundWorker1 sera-t-il “tué” par la suite? Si tel est le cas, cela prendra-t-il beaucoup de temps pour le terminer?
Ce codage va-t-il me mettre dans une boucle infinie?
Vous pouvez utiliser quelque chose comme ceci (pour plus d’informations sur l’abandon des threads gérés et sur ThreadAbortException, voir “Plomber les profondeurs de ThreadAbortException using Rotor ” par Chris Sells):
public class AbortableBackgroundWorker : BackgroundWorker { private Thread workerThread; protected override void OnDoWork(DoWorkEventArgs e) { workerThread = Thread.CurrentThread; try { base.OnDoWork(e); } catch (ThreadAbortException) { e.Cancel = true; //We must set Cancel property to true! Thread.ResetAbort(); //Prevents ThreadAbortException propagation } } public void Abort() { if (workerThread != null) { workerThread.Abort(); workerThread = null; } } }
Usage:
backgroundWorker1 = new AbortableBackgroundWorker(); //... backgroundWorker1.RunWorkerAsync(); if (backgroundWorker1.IsBusy == true) { backgroundWorker1.Abort(); backgroundWorker1.Dispose(); }
Je suis d’avis que les discussions doivent être autant que possible responsables de leurs propres ressources, y compris de leur vivant.
C’est généralement une mauvaise idée de tuer des threads en dehors de leur champ d’application. Les applications conçues pour transmettre un message au thread pour se fermer ont tendance à avoir beaucoup moins de problèmes liés au comportement multithread.
Un thread doit surveiller ce message, qui peut être aussi simple qu’un jeu booléen par un autre thread et lu par ce thread de surveillance, de manière opportune et se fermer proprement dès que possible.
Cela signifie que s’il doit chercher le message:
Le thread qui le ferme avec le message devrait attendre (mais ne pas arrêter l’interface graphique, bien sûr).
Notez qu’il existe d’autres possibilités pour les environnements threadés avec des fonctionnalités spécifiques, telles que le cas où les threads peuvent se marquer comme étant résiliables à volonté, pour permettre une destruction plus efficace des données externes.
Mais il est généralement plus facile de simplement structurer votre application pour laisser un fil conducteur à son propre destin.
Je mets un ensemble qui (je pense) fait le travail. S’il vous plaît laissez-moi savoir si im waaaay off. Voici un exemple simple de son fonctionnement.
var backgroundWorker = new BackgroundWorker(){WorkerSupportsCancellation = true}; backgroundWorker.DoWork += (sender, args) => { var thisWorker = sender as BackgroundWorker; var _child = new Thread(() => { //..Do Some Code }); _child .Start(); while (_child.IsAlive) { if (thisWorker.CancellationPending) { _child.Abort(); args.Cancel = true; } Thread.SpinWait(1); } }; backgroundWorker.RunWorkerAsync(parameter); //..Do Something... backgroundWorker.CancelAsync();
Étant donné que le travailleur d’arrière-plan fait partie du pool de threads, nous ne voulons pas l’abandonner. Mais nous pouvons exécuter un thread en interne, ce qui peut permettre à un avortement de se produire. Le backgroundWorker s’exécute alors jusqu’à ce que le thread enfant soit complet ou que nous lui signalions de tuer le processus. Le thread de travail en arrière-plan peut alors retourner dans le pool de lecture. En règle générale, je vais envelopper cette classe dans une classe d’assistance et passer par la méthode de délégation que je souhaite que le thread d’arrière-plan exécute en tant que paramètre et l’exécuter dans le thread enfant.
S’il vous plaît quelqu’un me le faire savoir si im bash ma tête contre un mur, mais il semble fonctionner correctement .. Mais c’est le problème avec les threads n’est-ce pas .. les résultats variables que vous pouvez obtenir lorsque vous l’exécutez à des moments différents.
public class abortableBackgroundworker: BackgroundWorker { public bool Kill = false; protected override void OnDoWork(DoWorkEventArgs e) { var _child = new Thread(() => { while (!Kill) { } e.Cancel = true;//..Do Some Code }); _child.Start(); base.OnDoWork(e); } }
vous définissez kill à true pour tuer le thread et ne pas abandonner le problème 🙂
J’avais le même problème, je ne suis pas sûr que cela aidera, mais je suppose que votre agent d’arrière-plan a une boucle ou qu’il quitterait. Ce que vous devez faire est de mettre votre boucle dedans.
Mettez dans votre arrière-plan:
while (backgroundworker1.CancellationPending == false) { //Put your code in here }
Pour tuer ce backgroundworker, vous pouvez insérer votre bouton:
BackgroundWorker1.CancelAsync()
J’espère que ça aide.