Come “uccidere” lo sfondo lavoratore completamente?

Sto scrivendo un’applicazione per Windows che esegue ripetutamente una sequenza di azioni IO digitali.

Questa sequenza di azioni inizia quando l’utente fa clic su un pulsante “START”, ed è fatto da un lavoratore in background in backgroundWorker1_DoWork ().

Tuttavia, ci sono occasioni in cui ottengo il messaggio di errore “Questo backgroundworker è attualmente occupato …….”.

Sto pensando di implementare quanto segue nel codice, utilizzando un ciclo while per “uccidere” il worker in background prima di iniziare un’altra sequenza di azioni:

if (backgroundWorker1.IsBusy == true) { backgroundWorker1.CancelAsync(); while (backgroundWorker1.IsBusy == true) { backgroundWorker1.CancelAsync(); } backgroundWorker1.Dispose(); } backgroundWorker1.RunWorkerAsync(); 

Penso che la mia preoccupazione principale sia che il backgroundWorker1 sarà “ucciso” alla fine? Se lo farà, ci vorrà molto tempo per completarlo?

Questa codifica mi porterà in un ciclo infinito?

Puoi usare qualcosa del genere (per maggiori informazioni sull’aborto di thread gestiti e su ThreadAbortException vedi ” Scandire le profondità di ThreadAbortException usando Rotor ” di 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; } } } 

Uso:

 backgroundWorker1 = new AbortableBackgroundWorker(); //... backgroundWorker1.RunWorkerAsync(); if (backgroundWorker1.IsBusy == true) { backgroundWorker1.Abort(); backgroundWorker1.Dispose(); } 

Sono dell’opinione che i thread dovrebbero essere responsabili delle proprie risorse il più ansible, compresa la propria vita.

Di solito è una ctriggers idea uccidere thread esterni al loro ambito. Le applicazioni progettate per passare un messaggio al thread per chiudersi tendono ad avere molto meno problemi relativi al comportamento multi-thread.

Un thread dovrebbe monitorare questo messaggio, che può essere semplice come un insieme booleano di un altro thread e letto da quel thread di monitoraggio, in modo tempestivo e chiudersi correttamente non appena ansible.

Ciò significa che dovrebbe cercare il messaggio:

  • nel suo ciclo principale, se esiste.
  • periodicamente in tutti i loop di lunga durata.

Il thread che lo interrompe con il messaggio dovrebbe attendere (ma non interrompere la GUI, ovviamente).

Si noti che esistono altre possibilità per gli ambienti con thread con funzionalità specifiche, ad esempio il caso in cui i thread possono contrassegnare se stessi cancellabili a piacimento, per consentire che l’uccisione esterna sia più sicura.

Ma di solito è ancora più semplice architettare la tua applicazione per lasciare un master filo del proprio destino.

Ne ho messo uno che (penso) fa il lavoro. Per favore, fammi sapere se sto bene. Ecco un semplice esempio di come funziona.

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

Poiché il worker in background fa parte del pool di thread, non lo vogliamo abortire. Ma possiamo eseguire internamente un thread su cui possiamo permettere che si verifichi una interruzione. Il backgroundWorker quindi viene eseguito fino a quando il thread secondario non è completo o viene segnalato ad esso per interrompere il processo. Il thread di background worker può quindi tornare nel pool di lettura. In genere lo racchiuderò in una class helper e passerò attraverso il metodo delegate che voglio che il thread in background venga eseguito passato come parametro ed eseguito nel thread secondario.

Per favore qualcuno mi faccia sapere se sto sbattendo la testa contro un muro, ma sembra funzionare bene .. Ma questo è il problema con i fili, non è vero .. i risultati variabili che puoi ottenere quando lo esegui in tempi diversi.

 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); } } 

imposta kill to true per uccidere il thread e nessun problema di interruzione 🙂

Stavo avendo lo stesso problema, non sono sicuro che ciò possa essere d’aiuto, ma suppongo che il tuo assistente in background abbia un ciclo all’interno o che esca. Quello che devi fare è inserire il tuo ciclo all’interno.

Metti il ​​tuo lavoratore in background:

 while (backgroundworker1.CancellationPending == false) { //Put your code in here } 

Per uccidere questo backgroundworker, puoi inserire il tuo pulsante:

 BackgroundWorker1.CancelAsync() 

Spero che aiuti.