How to make BackgroundWorker ProgressChanged events execute in sequence?

Andris picture Andris · Nov 7, 2011 · Viewed 23.2k times · Source

Consider the following code:

private static BackgroundWorker bg = new BackgroundWorker();

static void Main(string[] args) {
  bg.DoWork += bg_DoWork;
  bg.ProgressChanged += bg_ProgressChanged;
  bg.WorkerReportsProgress = true;
  bg.RunWorkerAsync();

  Thread.Sleep(10000);
}

static void bg_ProgressChanged(object sender, ProgressChangedEventArgs e) {
  Console.WriteLine(e.ProgressPercentage);
  Thread.Sleep(100);
  Console.WriteLine(e.ProgressPercentage);
}

static void bg_DoWork(object sender, DoWorkEventArgs e) {
  for (int i = 0; i < 10; i++) {
    bg.ReportProgress(i);
  }
}

When run I get the following output:

0 1 1 2 0 3 2 3 5 4 4 6 5 7 7 8 6 9 8 9

I understand that the issue is a race condition between the threads that BackgroundWorker starts for each call to ReportProgress.

How can I make sure that the whole body of each bg_ProgressChanged gets executed in the order I have called them? That is I would like to get

0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9

as a result.

Answer

SLaks picture SLaks · Nov 7, 2011

BackgroundWorker raises ProgressChanged events on the current SynchronizationContext of the thread that called RunWorkerAsync().

The default SynchronizationContext runs callbacks on the ThreadPool without any synchronization.

If you use BackgroundWorker in a UI application (WPF or WinForms), it will use that UI platform's SynchronizationContext, which will execute callbacks in order.