3

I am using the BackgroundWorker thread to perform a long task(basically reading a big xml file). For the first time the worker works fine as desired, but if I upload a second xml file, using the same background worker it works fine sometimes but most of the time the Backgroundworker's RunWorkerCompleted is fired even before the DoWork event. Some of the code is displayed below

    private void openFile_Click(object sender, RoutedEventArgs e)
    {
          // Code removed for brevity
  worker = new BackgroundWorker();
            worker.RunWorkerAsync();
            worker.DoWork += new DoWorkEventHandler(worker_DoWork);
            worker.WorkerReportsProgress = true;
            worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);
            worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
       }

        void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        DataImport();
        //worker.Dispose();
        //worker.Disposed += new EventHandler(worker_Disposed);
        //worker.DoWork -= worker_DoWork;
        //worker.RunWorkerCompleted -= worker_RunWorkerCompleted;
        //worker = null;
        //GC.Collect(GC.GetGeneration(worker), GCCollectionMode.Forced);
    }

worker is a globally defined variable. What is wrong here I am not getting. Kindly help

Vikram
  • 1,617
  • 5
  • 17
  • 37
  • A few hints for Completed: Don't call `GC.Collect()`, Do inspect `e.Error`. – H H Jul 29 '13 at 13:43
  • 1
    Not possible to answer w/o seeing at least an outline of DoWork(). – H H Jul 29 '13 at 13:45
  • If your DoWork function spawns a thread to perform its work, and you don't do a .Join(), DoWork will return instantly. But as @Henk said, need to see what DoWork does. – bland Jul 29 '13 at 13:56

5 Answers5

9

You should add the DoWork-event handler (and all other event handler, too) before calling RunWorkerAsync().

Otherwise, it could happen that RunWorkerAsync does practically nothing.

sloth
  • 99,095
  • 21
  • 171
  • 219
  • 1
    True, but does not really explain the symptoms "is fired even before the DoWork event". – H H Jul 29 '13 at 13:44
  • Might also want to mention, since he's re-using the worker, that he should make sure not to add the event handlers multiple times. – Jim Mischel Jul 29 '13 at 14:26
  • @JimMischel Also, he's re-using the event handlers, so maybe the `RunWorkerCompleted` event that is fired does not belong to the "current" background worker. – sloth Jul 29 '13 at 14:37
  • The OP is creating a new Bgw each time. And the commented-out code really tries to eradicate the old one. Both are sufficient to exclude reuse of handlers. – H H Jul 29 '13 at 19:24
  • @DominicKexel Thanks a lot for the reply. But why is it like this, RunWorkerCompleted Event should execute only after the worker is done with its work irrespective of where we are assigning handler to the event. Any Idea ? – Vikram Jul 30 '13 at 07:28
  • 1
    @Vikram RunWorkerCompleted += ... is _not_ being invoked by you but by the BackgroundWorker. You're only assigning the work for it to go do when it determines it is the appropriate time to do so. More importantly you need to assign the DoWork+= before RunWorkerAsync() on the same concept - that BGW needs an assigned function when it determines it is time to handle a given event. RunWorkerAsync will start and when it determines resources are available enough, it will begin the assigned "DoWork". When "DoWork" has completed the BGW will know and will then look to see if "Completed" is assigned. – bland Aug 02 '13 at 12:55
2

It should be like this:

worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;

worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.ProgressChanged += 
    new ProgressChangedEventHandler(worker_ProgressChanged);
worker.RunWorkerCompleted += 
    new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);

worker.RunWorkerAsync();

RunWorkerAsync should be called after subscribing to the DoWork and RunWokerCompleted events.

Carsten
  • 11,287
  • 7
  • 39
  • 62
Vishal
  • 604
  • 1
  • 12
  • 25
2

you should check first that background worker is busy or not, using this....

        backgroundWorker1.DoWork += backgroundWorker1_DoWork;
        backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
        if (backgroundWorker1.IsBusy)
        {
            backgroundWorker1.CancelAsync();
        }
        else
        {
            backgroundWorker1.RunWorkerAsync();

        }
Mukesh Kumar
  • 2,354
  • 4
  • 26
  • 37
0

As said in https://stackoverflow.com/a/16809596/8029935, you can be blindly assuming that the worker has finished the job and produced a result when DoWork Method dies from an exception. Which is caught by BackgroundWorker and passed to the RunWorkerCompleted event handler as the e.Error property.

So, I suggest you must check that property using a try/catch statement.

0

If you Call another async function in your BackgroundWorker _DoWork event,

like;

    private void BackgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        somethingsToDoAsync();
        // somethingsToDoAsync() function is to ASYNC 
    }

_RunWorkerCompleted fires even before completed _Dowork event.

Change another function to not async.