3

I have a background worker that I've set up which I'd like to potentially restart after it completes. That is, after DoWork() has completed, if the result was not successful, I want to call RunWorkerAsync() again from within the RunWorkerCompleted() handler. Can I be assured that IsBusy=false when I'm inside RunWorkerCompleted()?

For example:

void myThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if ((e.Error == null) && !e.Cancelled && (bool)e.Result)
        // do stuff
    else
        myThread.RunWorkerAsync();
}

I can't seem to find confirmation of this behavior anywhere.

Michael Repucci
  • 1,633
  • 2
  • 19
  • 35
  • 1
    The answer from Hans Passant here (https://social.msdn.microsoft.com/Forums/vstudio/en-US/ad9a9a02-8a11-4bb8-b50a-613bcaa46886/backgroundworkerisbusy-question) is pretty good confirmation. – Michael Repucci Nov 20 '14 at 20:03
  • Interesting. It makes sense though, you don't want to change a potentially UI-bound property on the background thread. – Jonathan Allen Nov 20 '14 at 20:10
  • Right. Though it seems from the documentation cited here (http://stackoverflow.com/a/2806824/304620) that RunWorkerCompleted() will be called on the UI thread, thus allowing such operations therein. It's just unclear to me whether IsBusy will have already been set to false, or might remain true until RunWorkerCompleted() completes. – Michael Repucci Nov 20 '14 at 20:24
  • The code you posted is bad, if e.Error != null then you cannot assume anything about e.Result. And you'd better come up with a scheme to interlock with the UI, you rarely want to restart the BGW when the user closed the window. Or to close the window while the BGW is active. Other than that there is no problem calling RunWorkerAsync() again. – Hans Passant Nov 20 '14 at 21:03
  • Oh woops. Meant e.Error == null. Will edit. Thanks! – Michael Repucci Nov 20 '14 at 21:04

2 Answers2

1

I don't see any reason why not. By definition it is done, so IsBusy should always be false. And you are back on the UI thread where you belong.

Jonathan Allen
  • 68,373
  • 70
  • 259
  • 447
1

Unfortunately, the documentation is not clear on the question. On top of that, the code example for the IsBusy property as actually pretty awful, in that it spin-waits on the property and calls Application.DoEvents() in the loop.

That said, as others have suggested, the most sensible design is for the flag to be true only when the async worker is actually running. I.e. when the DoWork event handler returns, it should be set back to false. And indeed, if one looks at the implementation, one sees this:

private void AsyncOperationCompleted(object arg)
{
    isRunning = false;
    cancellationPending = false;
    OnRunWorkerCompleted((RunWorkerCompletedEventArgs)arg);
}

public bool IsBusy
{
    get
    {
        return isRunning;
    }
}

The isRunning flag here is what the IsBusy property returns, and it's what RunWorkerAsync() checks to see whether the exception should be thrown. As can be seen here, the implementation sets it back to false before raising the RunWorkerCompleted event.

So, yes…it's perfectly safe to call RunWorkerAsync() from the RunWorkerCompleted event handler.

Without this being documented, there's the remote possibility the implementation could change. But at this stage, I would be very surprised if that happened. Especially with the code being open-sourced, the implementation becomes as much a specification of behavior as anything else.

Peter Duniho
  • 68,759
  • 7
  • 102
  • 136