Gotcha! How to get BackgroundWorker.RunWorkerCompleted to cause “Cross-thread operation not valid” exceptions

Oh yeah, it’s "Messin’ With the Framework" week (or year?). It’s my life™.

I did nothing, really. Just adding a little piece of code into an existing Windows.Forms application.

However, my code ended up running into an InvalidOperationException "Cross-thread operation not valid: Control ‘NamesAreNotImportant’ accessed from a thread other than the thread it was created on."

And it goes to show, the culprit was RunWorkerCompleted calling from the same thread it did DoWork.

That is not supposed to happen! If you claim something else, a cohort of MVP’s will call you names …

Well, ask them about AsyncOperationManager and when it’s SynchronizationContext property is set to an instance of WindowsFormsSynchronizationContext in a Windows.Forms application.

Gotcha!

Only while a Windows.Forms message loop is running, which makes perfect sense, given that the whole Invoke shebang uses Windows messages all the way to marshal the calls back and forth across threads.

So, when you call BackgroundWorker.RunWorkerAsync from outside the message loop, e.g. before Application.Run(myMainForm), then you are in trouble.

Because the BackgroundWorker takes a hold on the SynchronizationContext current at the time of invocation of RunWorkerAsync, and relies on it’s Post method to marshal the event back to the caller, it may easily end up calling from the wrong thread.

Do not start a BackgroundWorker.RunWorkerAsync before or after Application.Run.

Thank you, Lutz Roeder, I would know diddly-squat without you.

Advertisements
This entry was posted in Coding Horror. Bookmark the permalink.

2 Responses to Gotcha! How to get BackgroundWorker.RunWorkerCompleted to cause “Cross-thread operation not valid” exceptions

  1. Henry says:

    Disassembling? 
    Me?
    Almost never!
    By chance, I might have taken a peek.
    But I didn’t inhale!
     

  2. Unknown says:

    I run into the same problem last week. In a WPF MVC application i wanted to do some async initializations before app.Run(). I wondered why RunWorkerCompleted handler not is running under the main thread.What you can do is something like this Application.Current.Dispatcher.Invoke(new Action(delegate { //or what ever… OnStatusUpdate(new StatusEventArgs("test")); }));but i would avoid it nevertheless if possible.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s