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 plac开发者_StackOverflow社区e?
If I can write thread-safe code, I should be able to modify control state safely. Then why is this restriction present?
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.
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.
.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.
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.
Windows supports many operations which, especially used in combination, are inherently not thread-safe. What should happen, for example, if while one thread is trying to insert some text into a text field starting with the 50th character, while another thread tries to delete the first 40 characters from that field? It would be possible for Windows to use locks to ensure that the second operation couldn't be begun until the first one completed, but using locks would add overhead to every operation, and would also raise the possibility of deadlock if actions on one entity require manipulation of another. Requiring that actions involving a particular window must happen on a particular thread is a more stringent requirement than would be necessary to prevent unsafe combinations of operations from being performed simultaneously, but it's relatively easy to analyze. Using controls from multiple threads and avoiding clashes via some other means would generally be more difficult.
Actually, as far as I know, that WAS the plan from the beginning! Every control could be accessed from any thread! And just because thread locking was needed when another thread required access to the control --and because locking is expensive-- a new threading model was crafted called "thread rental". In that model, related controls would be aggregated into "contexts" using only one thread, thus reducing the amount of locking needed. Pretty cool, huh?
Unfortunately, that attempt was too bold to succeed (and a bit more complex because locking was still required), so the good old Windows Forms threading model --with the single UI thread and with the creating thread to claim ownership of the control-- is used once again in wPF to make our lives ...easier?
精彩评论