views:

197

answers:

4

I know that if I am modifying a control from a different thread, I should take care because WinForms and WPF don't allow modifying control's state from other threads.

Why is this restriction in place?

If I can write thread-safe code, I should be able to modify control state safely. Then why is this restriction present?

+2  A: 

.NET reserves the right to access your control in the thread where you created it at any time. Therefore accesses that come from another thread can never be thread safe.

Ben Voigt
+7  A: 

Several GUI frameworks have this limitation. According to the book Java Concurrency in Practice the reason for this is to avoid complex locking. The problem is that GUI controls may have to react to both events from the UI, data binding and so forth, which leads to locking from several different sources and thus a risk of deadlocks. To avoid this .NET WinForms (and other UIs) restricts access to components to a single thread and thus avoids locking.

Brian Rasmussen
Add to that the interoperability with ActiveX controls (Brower control etc. - possibly indirectly through winforms integration) and you also have a COM legacy that is Single Threaded Appartement.
TomTom
Windows **doesn't** restrict access to the owning thread. That limitation is introduced by .NET.
Ben Voigt
@Ben: I didn't know that. I'll update my answer to reflect that. I'll check what the book says.
Brian Rasmussen
@Ben: I just checked the book, and it doesn't say that Windows does this, so the fault is all mine. Anyway, the reasoning still applies as restricting access to a single threads does avoid locking, so I hope the answer is still useful. Thanks for the info - I've been on .NET for too long, so I just assumed this was a Windows thing.
Brian Rasmussen
@Brian, @Ben: in addition, if I recall correctly, .NET didn't even enforce this in the debugger (via `Control.CheckForIllegalCrossThreadCalls`) until 2.0.
Michael Petrotta
+3  A: 

In the case of windows, when a control is created UI updates are performed via messages from a message pump. The programmer does not have direct control of the thread the pump is running on, therefore the arrival of a message for a control could possibly result in the changing of the state of the control. If another thread (that the programmer was in direct control of) were allowed to change the state of the control then some sort of synchronization logic would have to be put in place to prevent corruption of the control state. The controls in .Net are not thread safe; this is, I suspect by design. Putting synchronization logic in all controls would be expensive in terms of designing, developing, testing and supporting the code that provides this feature. The programmer could of course provide thread safety to the control for his own code, but not for the code that is in .Net that is running concurrently with his code. One solution to this issue is to restrict these types of actions to one thread and one thread only, which makes the control code in .Net simpler to maintain.

Steve Ellinger
A: 

You might be able to make your own code thread-safe, but there is no way for you to inject the necessary synchronization primitives into the builtin WinForm and WPF code that match up with the ones in your code. Remember, there are a lot of messages getting passed around behind the scenes that eventually cause the UI thread to access the control without you really ever realizing it.

Another interesting aspect of a controls thread affinity is that it could (though I suspect they never would) use the Thread Local Storage pattern. Obviously if you accessed a control on a thread other than the one it was created on it would not be able to access the correct TLS data no matter how carefully you structured the code to guard against all of the normal problems of multithreaded code.

Brian Gideon