views:

139

answers:

4

After exploding with excitement over learning about how to make thread-safe calls to Windows Form Controls, it got me thinking...

Why aren't all calls to Windows Form Controls thread-safe? Can anyone explain why? I would think it would reduce a lot of confusion for users of those controls.

+4  A: 

Because it would reduce performance and writing lock-free thread safe code is still an area of active research.

Darin Dimitrov
+1  A: 

To expand on Darin's answer:

Most of the time Windows Form Controls don't need to be thread safe as they are usually accessed from the UI thread.

Occasionally they do (as in your code for example).

So, adding the thread checking code would add an unacceptable performance overhead to the 95%+ of the cases where it's not needed.

ChrisF
+2  A: 

The actual problem is that windows forms uses native resources, such as GDI objects in order to render the forms/controls.

Those GDI resources can only be used from the thread that created them, most likely the main thread.

Thus, any call to a form/control that needs to update the gui and thus redraw using the GDI resources must be made on the main thread.

So incomming calls from other threads that want to do this, must be marshalled to the main thread. I'm not quite sure how this works behind the scenes, but I guess accomplish this by posting messages to the wnd proc of the form/component. once the main thread processes this message in the wndproc, it can invoke the actual code. And this would be very expensive performance wise.

Roger Alsing
Marshalling the call to the UI thread is only half the problem. You also have to get the return value back. As you say, marshalling involves posting messages, so to get the result back you have to roll your own back channel since PostMessage doesn't give you one, and it may take a lot of effort to so. Also, if you make a cross thread call to a thread which in handling that call has to make a cross thread call to you, what happens? Hidden cross thread marshalling is a bad thing (see COM for more examples why :))
Stewart
+6  A: 

The issue here is not one of thread safety. The methods are all "thread safe" in that they do not corrupt the state of the application when called simultaneously on multiple threads - it is just that thread safety includes throwing a wrong thread exception (can't remember what it is called).

What they have is thread afinity - they can only be called on one thread - sometimes referred to as the UI thread, although this is misleading because it implies there is only one. This is mainly because the OS calls they depend on have the same thread affinity rules.

Trust me - this is a good thing. When you think about the primary role of the "UI Thread" it all starts to become clear. The UI threads job is to take input from the users hands, through a keyboard or mouse, act upon it, and produce output in the form of pixels in response. There is only one user, and that user only has one set of eyes. The user expects to see everything they do happen on the screen, and most importantly they expect to see it happen in the order they did it. Multithreaded UI would make this very difficult to achieve - almost impossible.

The problem is that when you mix your background "worker" threads with the UI thread, you need to do a certain amount of marshalling to talk to the UI because you have to be on the UI thread to do it. Again, as I said, this is a good thing. Someone has to do this marshalling, else the user would see things happening in the wrong order and that is bad. The system could admittedly do it for you, and in some WIN32 calls it does - but this has problems. First of all, the system can't know what granularity you need the marshalling to occur at so you might end up being inefficient. Your operations might be better marshalled at a higher level than the system can understand. Secondly, the marshalling is expensive, and it punishes the developers who are doing the right thing and moving everything over to the UI thread correctly. So the system does the minimum thing it can, check if it is on the right thread and if not, throw an exception.

Stewart
This article seems to explain a bit more on thread affinity: http://www.bluebytesoftware.com/blog/2007/05/20/ThePerilsOfThreadAffinity.aspx
sheepsimulator
@sheepsimulator - that article is fine as it goes, and if you're writing a server, Joe is spot on the money. The problem here is that he isn't talking about the window manager. You can't queue UI events through a thread pool, because people expect their key presses to be handled in order. The UI has inherent thread affinity because there is only one screen, one keyboard and one user.
Stewart