views:

125

answers:

3

We know that it is not possible to execute code that manipulates the properties of any UI element from any thread other than the thread the element was instantiated on... My question is why?

I remember that when we used COM user interface elements, (in COM/VB6 days), that all UI elements were created using COM classes and co-classes that stored their resources using a memory model referred to as Thread-Local-Storage (TLS) , but as I recall, this was required because of something relaetd to the way COM components were constructed, and should not be relevant to .Net UI elements. Wha's the underlying reason why this restriction still exists? Is it because the underlying Operating System still uses COM-based Win32 API classes for all UI elements, even the ones manipulated in a managed .Net application ??

+2  A: 

AFAIK, it's more basic than even COM. It goes right down to the good ol' Windows API. I believe that windows in Windows are expected to be owned by a thread, period. Each thread has it's own message pump, dispatching messages to the windows it owns. It's a pretty fundamental construct of Windows -- maybe a bit archaic these days, but fundamental.

My sense of it is that this thread affinity helps for interoperability when you need to integrate WPF into Windows Forms apps, or if you need to monkey with a Windows object somewhere else in your app using a HWND that you got somewhere... It probably also is what allows older versions of Windows (XP) to host WPF apps without any major architectural changes to the OS itself.

Dave Markle
If you are correct, this could be averted/modfied when then the OS Api has been fully migrated to use managed code... But If, however, there is a more fundamental reason for this, then this might not be possible/.
Charles Bretana
As I understand it, there are other OS's out there that allowed this, and I believe the BeOS was one of them. They really tried to thread the hell out of that OS in anticipation of the future need for parallelism. I think each window had a couple of threads to it (a rendering thread and a UI thread, per *window*, not per application)....
Dave Markle
A: 

From http://msdn.microsoft.com/en-us/library/ms741870.aspx:

Historically, Windows allows UI elements to be accessed only by the thread that created them. This means that a background thread in charge of some long-running task cannot update a text box when it is finished. Windows does this to ensure the integrity of UI components. A list box could look strange if its contents were updated by a background thread during painting.

ebpower
Well, I can do this now, I just have to call BeginInvoke() on the UI Control element, to switch to the correct thread... Individual framework UI functions that need to be single threaded could be coded that way regardless of whether they are allowed to execute on one thread or another...
Charles Bretana
You might find BackgroundWorker useful: http://www.albahari.com/threading/part3.aspx#_BackgroundWorker.
ebpower
+1  A: 

It sounds like you're referring to WPF rather than generic Windows API programming. I'm no expert on WPF internals, but here are a few items on why keeping UI manipulations in one UI thread are a good idea:

  1. Avoid Deadlocks. When you have multiple threads running around, all shared resources have to be protected by some sort of lock. When there are multiple locks, there is a high risk of getting stuck in a deadlock - thread A owns lock 1 but is waiting on lock 2, thread B owns lock 2 but is waiting for lock 1. This can be avoided by strict order of lock acquisition, but human nature falls short.
  2. Reduce the need for costly locks. If you can require all UI ops to execute on the UI thread, you can eliminate a lot of locks required to protect internal data.
  3. Reduce the risk of creating window handles owned by threads that don't have message loops.

That last item is Win API related. When a window handle is created, it is bound to the thread that issued the CreateWindow call. Messages sent to that window handle will be placed in the message queue associated with that thread. If that thread does not process window messages, the window will be non-responsive - UI frozen. If another thread tries to SendMessage to that window, that thread will also be frozen waiting for the synchronous call to complete. This snowballs pretty quickly into ugliness all over. This is why it's important to make sure that you only create window handles on threads that are prepared to process window messages.

Why is a window handle's message queue bound to a specific thread? I don't know, but I'm sure the answer is not trivial.

dthorpe
All true. The beauty of WPF is that you get your own rendering thread, so your last scenario doesn't happen. You can enjoy your perfectly painting, totally unresponsive app to your heart's content in WPF! ;-)
Dave Markle
@dthpr[e, actually, no.. I'm not expert on WPF. I'm referring to standard .Net Winforms UI elements. And deadlocks occur from multi=Threading in correctly, not from single threading on the wrong thread... The restriction is more severe than requiring single-threading, it restricts code from executing (even in a single-threaded pattern) on any thread other than the one thread on which the UI element was created.
Charles Bretana