none
Wait for BackgroundWorker to complete

    Question

  • I have a function that returns a calculated value. Because the calculation can be very long I execute it through an BackgroundWorker. But now I have a problem, how do I, in the function, wait for the BackgroundWorker to complete? If I do this it freezes:

    while (backgroundWorkerReadData.IsBusy)
        Thread.Sleep(50);

    Maybe some code to wait for the RunWorkerComplete event to be triggered?
    Friday, May 01, 2009 2:28 PM

Answers

  • My problem is that I want to wait for the BackgroundWorker to be finished before I return the value, but that while block I wrote doesnt seem to work. So is there any other way? Im still a bit new to threading, but I'm willing to learn.
    I suppose the question to ask yourself here is why do you want to wait until the background worker is completed before you return your value.  In other words, "What am I going to do with the data that is returned?"  If you want to use the data that is returned to output something on the screen, then you can still use the RunWorkerCompleted event handler.  Just before ending your DoWork method, assign the "e.Result" value.  When the method terminates, the RunWorkerCompleted event handler will run.  When it does, cast the e.Result value that comes into the RunWorkerCompleted event handler to whatever type you want to use, and then update your UI. 

    My guess is that you're calling ReadData() from another method, and then you're using the result of that ReadData() method to bind something to the UI.  Take all the code below your call to ReadData() and place it in your RunWorkerCompleted event handler.  Change the method type of ReadData() to a void, and return nothing.  Remove the while loop.  At the top of the event handler for RunWorkerCompleted, cast e.Result to whatever type it needs to be and make a local variable of type double[][].  In that method do what you would do after returning from ReadData(). 

    Feel free to ask any more questions, but the above should certainly help you "asynchronize" your code. 

    David Morton - http://blog.davemorton.net/
    • Marked as answer by MagniWare Friday, May 01, 2009 3:14 PM
    Friday, May 01, 2009 3:11 PM

All replies

  • If you need to wait for the background worker to complete, don't use a background worker, use a synchronous operation.  There is no difference between starting a backgroundworker and blocking your thread to wait for it to complete than just running it synchronously without the background worker.  Allow the BackgroundWorker's RunWorkerCompleted event to do whatever you need to do.  My guess is that you need to move the code below the two lines you've listed into the event handler for RunWorkerCompleted. 
    David Morton - http://blog.davemorton.net/
    Friday, May 01, 2009 2:36 PM
  • Your question isn't clear.  It seems that you want a synchronous pattern.  With an asynchronous pattern you would process the data accessed by the background worker when the RunWorkerCompleted event is fired.  Here's a typical pattern:

        private void button1_Click(object sender, EventArgs e)
        {
          button1.Enabled = false;
          backgroundWorker1.RunWorkerAsync();
        }
        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
          //Do stuff
        }
        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
          //Do UI stuff with DoWork event stuff.
          button1.Enabled = true;
        }
    Friday, May 01, 2009 2:42 PM
  • But code beneat those 2 lines never run, my application freezes because it stays in the loop, even if the code that the background worker should execute is executed. Also the function of the RunWorkerCompleted event does not start.
    Friday, May 01, 2009 2:42 PM
  • Try AutoResetEvent.

    void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        // do something
        _resetEvent.Set(); // signal that worker is done
    }

    And use _resetEvent.WaitOne(); to wait


    Friday, May 01, 2009 2:45 PM
  • public double[][] ReadData()
            {

                stringLog = "Initializing...";
                if (backgroundWorkerReadData == null)
                {
                    backgroundWorkerReadData = new BackgroundWorker();
                    backgroundWorkerReadData.WorkerReportsProgress = true;
                    backgroundWorkerReadData.DoWork += new DoWorkEventHandler(backgroundWorkerReadData_DoWork);
                    backgroundWorkerReadData.ProgressChanged += new ProgressChangedEventHandler(backgroundWorkerReadData_ProgressChanged);
                    backgroundWorkerReadData.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorkerReadData_RunWorkerCompleted);
                }
                backgroundWorkerReadData.RunWorkerAsync();

                while (backgroundWorkerReadData.IsBusy)
                    System.Threading.Thread.Sleep(50);

                return doubleReturn; //doubleReturn is the value that is filled if the BackgroundWorker is complete.
            }

    My problem is that I want to wait for the BackgroundWorker to be finished before I return the value, but that while block I wrote doesnt seem to work. So is there any other way? Im still a bit new to threading, but I'm willing to learn.
    Friday, May 01, 2009 2:51 PM
  • That's a synchronous block.  Drop the backgroundWorker and move the code in the DoWork event into the block.
    Friday, May 01, 2009 2:58 PM
  • My problem is that I want to wait for the BackgroundWorker to be finished before I return the value, but that while block I wrote doesnt seem to work. So is there any other way? Im still a bit new to threading, but I'm willing to learn.
    I suppose the question to ask yourself here is why do you want to wait until the background worker is completed before you return your value.  In other words, "What am I going to do with the data that is returned?"  If you want to use the data that is returned to output something on the screen, then you can still use the RunWorkerCompleted event handler.  Just before ending your DoWork method, assign the "e.Result" value.  When the method terminates, the RunWorkerCompleted event handler will run.  When it does, cast the e.Result value that comes into the RunWorkerCompleted event handler to whatever type you want to use, and then update your UI. 

    My guess is that you're calling ReadData() from another method, and then you're using the result of that ReadData() method to bind something to the UI.  Take all the code below your call to ReadData() and place it in your RunWorkerCompleted event handler.  Change the method type of ReadData() to a void, and return nothing.  Remove the while loop.  At the top of the event handler for RunWorkerCompleted, cast e.Result to whatever type it needs to be and make a local variable of type double[][].  In that method do what you would do after returning from ReadData(). 

    Feel free to ask any more questions, but the above should certainly help you "asynchronize" your code. 

    David Morton - http://blog.davemorton.net/
    • Marked as answer by MagniWare Friday, May 01, 2009 3:14 PM
    Friday, May 01, 2009 3:11 PM
  • A good reason to have to wait for a backgroundworker: Suppose a from that uses a backgroundworker to do something, for instance perform every second a measurement that needs to be displayed on the screen (display is done using progress report). But now we want to close the form, or close the program. We don't want to just kill the thread, for we don't know whether it needs to do some nice cleanup.

    Therefore we need to ask the backgroundworker nicely to stop working, and do its final cleanup. We have to wait until the backgroundworker really is stopped before destructing it, or maybe before we use the results from the backgroundworker.

    Monday, July 15, 2013 9:14 AM
  • This would only work if the backgroundworker would stop automatically.

    But suppose the backgroundworker continues working until someone asks nicely to stop working and create its results. Example: a backgroundworker that regularly measures something, until stopped, and then has to report the average value of the measurements.

    So we have a start and stop button. Once your runworkercompleted is called, we know we can use the result, for instance to display it.

    But what if we want to close the form, or the program: we can't just kill the backgroundworker. We have to ask it nicely to stop and wait until it really is stopped before we can continue:

    private void OnFormClosed(...)
    {
        // stop backgroundworker
        worker.CancelAsync()
        // wait until really stopped before we use the results
        // = wait until worker completed is called
        // the only way I know this, is by waiting for
        // an event that is raised in the worker completed
        // function
    }



    Monday, July 15, 2013 9:21 AM