1

We are using continous backgroundworker and have problem stopping them correcty. We tried different versions:

bw.WorkerReportsProgress       = true;
bw.WorkerSupportsCancellation  = true;
bw.DoWork                     += new DoWorkEventHandler(bw_DoWork);
bw.ProgressChanged            += new ProgressChangedEventHandler(bw_ProgressChanged);
bw.RunWorkerCompleted         += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);    
evCompl                        = new AutoResetEvent( false );

private void bw_DoWork(object sender, DoWorkEventArgs e) {
    while(!bw.CancellationPending ) {
        // sleep or do time wasting stuff 
        bw.ReportProgress( 0, /*some Data*/ );
    }
    if( bw.CancellationPending ) {
        e.Cancel = true;
    }
    evCompl.Set(); 
}
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e) {
    Data d = (Data)e.Data;
    // sometimes do some Gui stuff with invoking
}
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)  {
   // ... 
}
protected virtual void Disposing( bool disposing )
{
     if( bw!=null ) {
         bw.CancelAsync();
         evCompl.WaitOne();

         bw.DoWork             -= new DoWorkEventHandler(bw_DoWork);
         bw.ProgressChanged    -= new ProgressChangedEventHandler(bw_ProgressChanged);
         bw.RunWorkerCompleted -= new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
         bw.Dispose();
     }
   }

Well, this variant sometimes end in a deadlock at

evCompl.WaitOne();

and also the the bw_RunWorkerCompleted is never called. Using timed wait, e.g. evCompl.WaitOne(2000)( what is a much higher value than a loop cycle can ever need) results in titme to time null pointer exceptions.

Another not really null pointer exception free variant was:

void Dispose( bool disposing )
{ 
    if( bw.IsBusy ) {
       bw.CancelAsync();
    }

    bw.DoWork             -= new DoWorkEventHandler(bw_DoWork );
    bw.RunWorkerCompleted -= new RunWorkerCompletedEventHandler( bw_completed );
    bw.ProgressChanged    -= new ProgressChangedEventHandler( bw_ProgressChanged );

    // ...
    if( disposing ) {
        bw.Dispose();
        bw = null;
    }
} 

But I thing the reason could be "bw=null" -> inside DoWork bw is used -> null pointer acces if bw was set to null before.

In the end I need a solid way to stop the bw in Dispose and ensure that it has stopped. We put a lot of checks for bw.CancellationPending to break the while loop as soon as possible. But every way I have tried had have some side effects.

And yes: I also read a lot of threads regarding that topic...

muffmolch
  • 113
  • 9
  • http://stackoverflow.com/questions/1731384/how-to-stop-backgroundworker-on-forms-closing-event – Matthew Watson Mar 09 '16 at 09:00
  • The linked solution is for Forms. We are using this kind of backgroundworkers inside forms, user controls and user defined classes. Thus the "cancel the closing event"-solution works only in one out of three... maybe in 1.5 out of 3 ;-) – muffmolch Mar 09 '16 at 09:33
  • Pretty unclear why it does not *always* produce deadlock. It certainly should, this just can't work. You'll have to call Set() in the DoWork event handler, the only way if you can't delay closing the form. It is still a race condition, you now have to make sure that the worker was started before you allow the form to close :) – Hans Passant Mar 09 '16 at 09:57
  • I see. You're right. Problem is: it does not enter the completed method at canceling in dispose. My fault...to many versions in mind ;-) Of course it cannot work in bw_RunWorkerCompleted... -> I'll edit the post – muffmolch Mar 09 '16 at 10:07

0 Answers0