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