What is the difference between options 1 and 2 in the following?
private void BGW_DoWork(object sender, DoWorkEventArgs e)
{
for (int i=1; i<=100; i++)
{
string txt = i.ToString();
if (Test_Check.Checked)
//OPTION 1
Test_BackgroundWorker.ReportProgress(i, txt);
else
//OPTION 2
this.BeginInvoke((Action<int, string>)UpdateGUI,
new object[] {i, txt});
}
}
private void BGW_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
UpdateGUI(e.ProgressPercentage, (string)e.UserState);
}
private void UpdateGUI(int percent, string txt)
{
Test_ProgressBar.Value = percent;
Test_RichTextBox.AppendText(txt + Environment.NewLine);
}
Looking at reflector, the Control.BeginInvoke() appears to use:
this.FindMarshalingControl().MarshaledInvoke(this, method, args, 1);
Which seems to eventually call some native functions like PostMessage(), couldn't exactly figure out the flow from reflector (pesky compiler goto optimizations)
Whereas BackgroundWorker.Invoke() appears to use:
this.asyncOperation.Post(this.progressReporter, args);
Which seems to eventually call ThreadPool.QueueUserWorkItem()
(I'm just guessing these are the relevant function calls for each case.) If I understand correctly, using the ThreadPool would not guarantee execution order whereas using the Post mechanism would. Perhaps that would be a potential difference ? (EDIT - I couldn't synthesize such a situation - call order seems to be preserved in both cases, at least in my simple tests.)
Thanks!
One big difference is that
Control.Invoke
will block until the UpdateGUI call has been executed and completed, whereasBackgroundWorker.ReportProgress
will not block (it will return immediately, before the BackgroundWorker raises the event).If you want them to behave the same, call
Control.BeginInvoke
(which doesn't block) instead.They are both the same. The call you're seeing in
BackgroundWorker
usesSynchronizationContext
. Indeed the default implementation of thePost()
method uses the thread pool, but when starting a Windows Forms app, the default synchronization context is replaced byWindowsFormsSynchronizationContext
, which actually callsControl.BeginInvoke()
.I've found a significant difference. Closing the form while the BGW is running will cause this.Invoke() and this.BeginInvoke() to throw an ObjectDisposedException. The BGW ReportProgress mechanism circumvents that. To enjoy the best of both worlds, the following pattern works nicely