This doesn't answer your question, but I try as far as possible to avoid this problem.
Because of the existence of data binding, I make sure the only code that can update business objects is code that's running on the GUI thread.
For async operations, I adopt a pattern of:
- Send work to the background: Trigger an async operation -- say, a thread pool item -- from the GUI thread. Pass only plain data types into the thread pool, and receive only plain data types back. If business objects are used by the thread pool, make sure that these are either brand new ones (that haven't been data bound yet), or are clones of the originals (to avoid concurrent access)
- Do the work and obtain a result: Execute the async operation on a background thread. The background thread code will own the 'safe' objects given to it by the GUI; it won't have any interaction with the rest of the application.
- Unpack the result in the GUI: When the async operation is finished, it triggers an 'I am complete' event on the GUI thread. In response, the GUI thread can unpackage any results from the background operation and merge them back into the main business objects, safe in the knowledge that it won't be dealing with concurrent access.
I can recommend the System.Threading.Tasks.Task
class as an abstraction around most of the above steps. It's new in .NET 4.0, but it's also available as a separate download for .NET 3.5 apps.
Steps (1) and (2) are what the Task
class does without any customisation. You can achieve (3) by spawning a separate Task
from inside the background thread and specifying TaskScheduler.FromCurrentSynchronizationContext
as a scheduler. (You'll need to call FromCurrentSynchronizationContext
from the GUI thread, in step (1), not from the background thread.)