Furthermore, even if your application is not using COM interop explicitly,
Windows Forms uses it internally for things like common dialogs, drag and
drop, and the clipboard. If the application makes use of any of these
features and you replace [STAThread] with [MTAThread], then you will
experience some very strange bugs. For example, try changing the UI thread
to [MTAThread] and display an OpenFileDialog. If you select 'My Computer'
you will find that it no longer displays the expected contents.

Fernando Tubio

----- Original Message -----
From: "Russ Alan" <[EMAIL PROTECTED]>
Sent: Tuesday, September 27, 2005 4:21 PM
Subject: Re: WaitHandle.WaitAll STA thread.


While I did not take time to read in depth, skimming through I saw nothing I
disagree with, nor anything that contradicts my position (which has not
changed).

I agree that even though this touches on several potentially interesting
topics, we probably shouldn't go too far down the COM road, particularly
since there is no COM requirement specified.  But parts of it are highly
relevant since the discussion involves implications resulting from the
"default" STA attribute along with proposals to just replace it with MTA in
order to circumvent the restriction (which was explained by Chris).  And
furthermore, it is quite possible that COM is being used within the bowels
of some library, even if the author of the client application is not aware
of it.  If you mark your GUI thread for the MTA, and that thread calls into
said library, which results in a CoCreate of a "free" threaded COM object,
then that object will be directly accessible by the GUI thread.  There are
several implications to that.

1) Since the object is marked "free", it can legally block any call (thread)
that comes into it for an indefinite time, maybe even infinite.  Of course
that means the GUI is completely unresponsive for that length of time.  If
there is a button that says "Cancel Call" or something, tough luck.

2) Again, the object is marked "free", so it can make use of as many threads
as it likes.  It can also use any of those threads to "call back" (fire
events) to the "client".  Since this client is "in the MTA", the callback
interface will not be "marshaled" into the MTA, so those threads will be
used to make the call directly rather than transferring to the GUI thread.
That of course has major implications when updating the UI in response to
those callbacks, or even when just changing values of instance/static
fields.  Without writing any code to explicitly do so (and likely being
completely unaware of the situation) you just turned your app into a
multi-threaded app with all the associated sync and deadlock avoidance
requirements, but you have absolutely nothing in your code to make that
obvious to yourself or anyone else until you start getting bizarre runtime
bugs.

And the list goes on far beyond my interest in detailing or contriving
examples...

On the other hand, if you follow the "rules" and make sure that GUI threads
are mapped as STAs, then that "free" object is created on a MTA thread and
the caller (GUI thread) gets a proxy.  Calls out to the object are only
logically blocked, and windows messages can still be dispatched.  Exactly
what messages are dispatched depends on the message filter installed.  And
those callbacks (for progress notification perhaps?) made on other threads
no longer execute straight into the unsuspecting client, but rather are
automatically transferred onto the GUI thread.  And this works even if that
GUI thread is "logically blocked" in the call out which may well have
triggered the call back.  This in turn introduces the possibility of
"reentrancy" (what Chris refers to as "recursion", though IMO the term is
too limited) but that is an even more difficult issue and a totally
different (HUGE) discussion.

Now, assuming that you have a trivially simple APP and can definitively
state that it does not nor ever will use COM, a third party library that
might use COM, or current/future FCL features that will/might use COM.  And
assuming you can guarantee that all current and future developers working on
the project understand the risks and limitation.  Then we can reasonably
ignore those COM specific issues.

In that very limited case, I would suggest we should leave the attribute out
all together rather than falsify things with an MTA attribute just to get by
the safety net.  But that still leaves us with basic Windows programming
issues which indicate that the GUI thread can not block without risking
similar issues from within the OS itself.

To bring this to a close (for me at least), I maintain that any design which
requires you to "hard block" the GUI thread, even for a few ms, needs some
architectural work to eliminate that requirement.  How it might be
eliminated depends on many things not currently defined.  I've put forth my
reasons as well as I know how without being even more verbose and
repetitive.  If anyone does decide to mark a GUI thread as MTA, or
arbitrarily block a GUI thread, then I can only hope that you have access to
someone who understands the "plumbing" well enough to help you figure out
what's going on when you run into the (IMO) inevitable difficult to
reproduce/fix problems that result from such actions.

Russ

-----Original Message-----
From: Unmoderated discussion of advanced .NET topics.
[mailto:[EMAIL PROTECTED] On Behalf Of Peter Ritchie
Sent: Saturday, September 24, 2005 5:24 AM
To: ADVANCED-DOTNET@DISCUSS.DEVELOP.COM
Subject: Re: [ADVANCED-DOTNET] WaitHandle.WaitAll STA thread.


I'll concede there is a difference in responsiveness of the GUI when making
a blocking cross-apartment COM call with STAThread and MTAThread. STAThread
will be *more* responsive than MTAThread--STAThread will repaint but the
title may append "(Not Responding)". The "GUI Thread" will still be blocked.
The application will not get any more GUI events while blocked on that COM
method (there are exceptions; but, this is the general case).  But, any
other type of call that is blocking will not repaint the GUI.

I try and clarify my comment on one thread in STA: an application can start
any number of threads it wants in an STA; but, only one thread should do any
COM interop (I don't know if "at a time" is valid; but it certainly wouldn't
be safe).  If you want more than one of your threads to do COM interop they
better be in an MTA or deadlocks may ensue (assuming you're communicating
with any particular STA object on only one of your threads).

If we get back to the original question regarding WaitHandle.WaitAll() and
your suggestion that a WinForm application should never be anything other
than STAThread:  This suggests that WaitHandle.WaitAll cannot be used with a
WinForm application (without, of course, starting up another thread
apartment, as MTA, and using WaitHandle.WaitOne to wait for that MTA thread.
But, as Chris Brumme points out on his blog [1], this is a bad idea).

My assumption was that the application did not use COM (which has neither
been confirmed nor denied) and the application needed to wait for more than
one synchronization object at a time.  In this case, MTAThread will not
affect the application other than the effect of enabling WaitAll().

I'm avoiding going OT by discussing a WinForm application that spawns
multiple threads to use COM interop to communicate with more than one MTA
COM object. But, it would be an interesting discussion.

[1] http://blogs.msdn.com/cbrumme/archive/2004/02/02/66219.aspx

http://www.peterRitchie.com/

On Fri, 23 Sep 2005 13:30:51 -0700, Russ Alan <[EMAIL PROTECTED]> wrote:

<snip>

===================================
This list is hosted by DevelopMentorĀ®  http://www.develop.com

View archives and manage your subscription(s) at http://discuss.develop.com

===================================
This list is hosted by DevelopMentorĀ®  http://www.develop.com

View archives and manage your subscription(s) at http://discuss.develop.com

Reply via email to