In my program I use BackgroundWorker in order to perform some operations in the background. However, a moment has surfaced:

BackgroundWorker worker = new BackgroundWorker(); worker.DoWork += delegate (object sender, DoWorkEventArgs e) { }; worker.RunWorkerCompleted += delegate (object sender, RunWorkerCompletedEventArgs e) { Console.WriteLine(System.Threading.Thread.CurrentThread.ManagedThreadId); }; Console.WriteLine(System.Threading.Thread.CurrentThread.ManagedThreadId); worker.RunWorkerAsync(); 

displays different stream IDs. I assumed that the BackgroundWorker made so that the result of the execution was transferred to the main thread. I am wrong?

From MSDN :

The methods that handle the ProgressChanged and RunWorkerCompleted have access to the application's user interface, as these events are raised on the thread that called the RunWorkerAsync method . However, the DoWork event DoWork cannot work with user interface objects, since it runs in a background thread.

UPD:

  System.ComponentModel.BackgroundWorker worker = new System.ComponentModel.BackgroundWorker(); worker.DoWork += delegate (object sender, System.ComponentModel.DoWorkEventArgs e) { Console.WriteLine("DoWork: " + System.Threading.Thread.CurrentThread.ManagedThreadId); (sender as System.ComponentModel.BackgroundWorker).ReportProgress(50, null); }; worker.RunWorkerCompleted += delegate (object sender, System.ComponentModel.RunWorkerCompletedEventArgs e) { Console.WriteLine("RunWorkerCompleted: " + System.Threading.Thread.CurrentThread.ManagedThreadId); }; worker.ProgressChanged += delegate (object sender, System.ComponentModel.ProgressChangedEventArgs e) { Console.WriteLine("ProgressChanged: " + System.Threading.Thread.CurrentThread.ManagedThreadId); }; Console.WriteLine("MainProcess: " + System.Threading.Thread.CurrentThread.ManagedThreadId); worker.WorkerReportsProgress = true; worker.RunWorkerAsync(); 

gives out:

MainProcess: 9

DoWork: 12

ProgressChanged: 6

RunWorkerCompleted: 12

  • Do you do all this in a console application? Or in winforms? - PashaPash
  • Wpf. Who cares? - Dmitry Chistik
  • In the application will be guided to work as expected, and such results, as I understand it, are obtained in the console? Here it is in context (oh, I must remember ...) - Alexander Petrov
  • WPF is gui, but not console - Dmitry Chistik
  • and how exactly you launch it under WPF? where exactly is the code entered? - PashaPash

1 answer 1

BackgroundWorker calls ProgressChanged and RunWorkerCompleted via SynchronizationContext . It uses SynchronizationContext.Current at the time of the RunWorkerAsync call.

Those. if you called RunWorkerAsync from a thread associated with a UI - for example, you hung up the code from a question on a synchronous ButtonClick - the main case for which BackgroundWorker developed

 private void button_Click(object sender1, RoutedEventArgs ee) { System.ComponentModel.BackgroundWorker worker = new System.ComponentModel.BackgroundWorker(); // ... snip Console.WriteLine("MainProcess: " + System.Threading.Thread.CurrentThread.ManagedThreadId); worker.WorkerReportsProgress = true; worker.RunWorkerAsync(); } 

the context associated with the UI thread will be captured:

 MainProcess: 9 DoWork: 13 ProgressChanged: 9 RunWorkerCompleted: 9 

And if you run your code in a stream in which there is no SynchronizationContext.Current anymore - then the forwarding of events will not work - because they have nowhere to redirect:

 private void button_Click(object sender1, RoutedEventArgs ee) { ThreadPool.QueueUserWorkItem((o) => StartWorker()); } private static void StartWorker() { System.ComponentModel.BackgroundWorker worker = new System.ComponentModel.BackgroundWorker(); // ... snip Console.WriteLine("MainProcess: " + System.Threading.Thread.CurrentThread.ManagedThreadId); worker.WorkerReportsProgress = true; worker.RunWorkerAsync(); Thread.Sleep(10000); } 

And the events just work in the streams taken from the pool, so as not to interrupt DoWork ()

Result:

 MainProcess: 12 DoWork: 13 ProgressChanged: 14 RunWorkerCompleted: 14 
  • Everything earned, pushed in the delegate app.Startup . app.Startup . Thanks for the answer! - Dmitry Chistik