Search code examples
.netwinformsbackgroundworker

Run BackGroundWorker in RunWorkerCompleted WinForms .net


I would know if it's "dangerous" Run A Backgrounworker2 in a RunWorkerComplete1 like this :

public void backgroundworker1RunComplete (Object sender , RunworkerCompleteEvent e)
{
    Backgroundworker2.runAsync();
}

Could be any deadlocks , various problems , etc? Becouse maybe i have only 2 alternatives :

Run Backgrounworker2 async in RunComplete1 or Use a ManualReset Event where i reset when i enter in BackGroundWorker DoWork1 and i Set() in WorkerComplete1

Number 1)

  private void BackgroundWorker1RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
  {
       backgroundWorker2.RunAsync();
  }

Number 2)

 private void BackgroundWorker1RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
  {
       manualReset.Set();  
  }

 private void BackGrounWorker2DoWork(Object sender , DoWorkEventArgs e)
 {
   manualReset.WaitOne();
  //Do Stuff
 }

Solution

  • background threads starting background threads (which is basically what you're doing here) is perfectly valid. I've seen and built algorithms that depend on just that, and there was even one where the same BGW restarted itself with a different command which triggered different logic (not my design, and I had my issues with it, but it got the job done).

    You just have to make sure you know what you (and your background threads) are doing, and what they shouldn't be doing:

    • Make sure there are no possible deadlocks, where both BGWs are waiting for the other to complete. In this case BGW1 launches BGW2 (which hasn't been running) and seems to be done after that, so this is unlikely. However, if both run at the same time and wait for the other to complete at any given point, or acquire locks on different objects, both of which are needed by both BGWs, there can be issues.

    • Don't ever try to directly get or set property/field values, or call methods, on a form from its BGW. If you must do this, use Control.Invoke or Control.BeginInvoke. You can avoid having to know the difference with a simple extension method or two.

    Here's that extension method (seems to be a bug in the formatter; can't put a code block in the middle of a list):

    public static void InvokeIfNecessary(this Control ctrl, Action action)
    {
        if(ctrl.InvokeRequired)
        {
           ctrl.Invoke((MethodInvoker)action);
           return;
        }
    
        action();
    }
    

    You can create other variations on this to take or return values, but with judicious use of external closures you can use this for almost anything.

    • Don't forget to wait for, or cancel, BGWs when closing their containing Form. This may require you to structure the doWork method (and long-running methods it calls directly) to know if and when to quit when signalled from outside.