Thanks Shawn, your insight has been analysed :) and after a bit of playing around with some hypothetical architectures I have to agree with you. I did end up with a message loop..
If I were to boil-down my original rant to its essence, I would still say this, however: wouldn't it be great if the UI thread wasn't tagged as STA, but rather that it was just like any old thread? This would mean you still have a single thread dispatching events to event handers, but your window objects would instead be written to be 100% threadsafe and, for example, you could Move a window to a new location by: myForm.Left = 77; from *any* thread, *without* using Invoke(). (Which evidently I have an aversion to :p ) Yes the programmer would have to use lock { } if they wanted to do more than one thing to the window and have it be atomic (like myForm.Left = myForm.Left + 77, for example), but to me the real problem here is that we still *have* unthreadsafe code in the first place. For example, the concept of Unsafe code in C# is probably going to be phased-out altogether at some point in the future. It's not inconceivable to me that unthreadsafe code will also be phased out in this way, making way for a truly unified system (i.e. not MTA|STA with a line down the middle.) If that's hard for the programmer to do in terms of sync plumbing etc. then perhaps the language itself is defficient? Anyway I just had to add that final point; sorry if this has bored anyone :| Jade Burton -----Original Message----- From: Moderated discussion of advanced .NET topics. [mailto:[EMAIL PROTECTED] Behalf Of Shawn A. Van Ness Sent: Tuesday, 24 February 2004 7:20 PM To: [EMAIL PROTECTED] Subject: Re: [ADVANCED-DOTNET] Thread with message pump (UI thread) Jade, I feel your pain. But I think if you really followed it through -- as you say, starting from a "perfect world" model and working back toward pragmatism -- you'd end up with something very similar to Windows's current single-threaded message queue architecture. At the end of the day, it's not the UI thread or its message-pump that's important -- it's the *queue* that adds value to our apps. By letting the OS manage the queue of UI events for our apps to process, one at a time (no matter the thread id!) we're ensured that a lot of bad things won't happen: keyboard and mouse messages will be handled in the relative order that they occurred; only one paint message will be active at a time; no more than one timer message will queue up; paint messages will never be delayed in favor of mousemove messages, ... etc. Contrast: If these events came in asynchronously, on arbitrary background threads, any event could be preempted at any time, by any other. Imagine the chaos! The OS might still guard against reentrancy, but it would be sheer madness, nonetheless: input messages would be handled out of order, timers would fire in the middle of repaints, etc etc. Under stress, our apps would behave a hundred times flakier than they currently do. (And they're already so bad, Chris Sells is having family problems... and with the recent spate of viruses and email worms, who among us hasn't apologized to a non-techie friend or family member, lately?) http://www.sellsbrothers.com/spout/#On_Behalf_of_Software_Engineers,_Im_Sorr y The 100% pure, completely-asynchronous event model just isn't practical -- it's too chaotic. So. Given that there's high value in letting the OS queue up messages for us, and feed them to us one at a time, in proper order and priority... this debate really just boils down to a push- vs pull-model for WinMain boilerplate. Currently, we have a pull-model: void WinMain() { MSG msg; while (GetMessage(&msg)) { DispatchMessage(&msg); } } That's not too much to ask, in the way of application boilerplate. And even though they may sometimes look less OO than their push-model counterpars, I think SAX vs. XmlReader has shown that pull-model APIs are more flexible. http://msdn.microsoft.com/library/en-us/cpguide/html/cpconComparingXmlReader ToSAXReader.asp Cheers, -Shawn http://www.windojitsu.com/ -----Original Message----- From: Jade Burton [mailto:[EMAIL PROTECTED] Sent: Monday, February 23, 2004 15:16 Subject: Re: Thread with message pump (UI thread) Thanks J.Merril - so it's fair to say the current split model is due to both technical limitations (i.e. it is infeasible for every single form call to be transparently Invoke'd) and compatibility issues relating to legacy code/systems. When I design stuff I like to start with a "perfect world" architecture and then gradually compromise the design backwards (which usually involves adding complexity) until I have something practical. In a "perfect world" there would be no message pump-related code, nor would there be a distinction between "worker" and "UI" threads. [You may say I'm a dreamer, but I'm not the only one...] >(Anyway, does it really make sense to have the worker thread stop dead with a message box while the user is interacting with the main UI? I don't think so. So the main UI should display the message box.) I respectfully disagree. ;) The worker thread in this example (i.e. get some data from the user, process it) could not continue until it has the data from the user, so of course it's going to block. [Think of the user as just another peripheral device connected to the computer!] I think all the objects of the UI should be just like all other objects. In theory I don't see a problem with making worker threads interact with these UI elements directly. >You could go ahead and call form.SetSomething if you have no concern that the form might be in the middle of some operation -- perhaps caused by the user -- that might cause either SetSomething or the active operation to work incorrectly due to lack of synchronization. (Don't get me wrong, this is not how I currently write programs - I understand the reasons for not calling form methods from multiple threads..) >The form.Invoke model is rather elegant compared to -- for example -- constructing a raw Windows message (with an application-custom message ID and message format) and calling PostMessage, having modified the window procedure for the form to recognize the message and call the right routine in response. (Most programmers could not take advantage of multi-threading at all before .NET, because of the complexities involved.) Yes it is better than before. Everything is relative, I guess.. Now that we finally do have access to such "advanced" concepts as multi-threading (how long has MT been around now, 30 years?) I think we'll see a shift away from "one optimised C++ worker thread does low-level image processing" to a much higher level usage: "user clicks menu item which creates a new 'logic' thread to show a dialog, get some data, process it, show a result dialog, then exit thread".. Now that's elegant. Jade Burton -----Original Message----- From: Moderated discussion of advanced .NET topics. [mailto:[EMAIL PROTECTED] Behalf Of J. Merrill Sent: Tuesday, 24 February 2004 1:53 AM To: [EMAIL PROTECTED] Subject: Re: [ADVANCED-DOTNET] Thread with message pump (UI thread) The reason that you can't (safely) call arbitrary methods of the form from within another thread is that doing so could only work reliably if every bit of WinForms code -- and every bit of your application that ran as a result of the user's interaction with the UI -- were written to be both 100% thread-safe and re-entrant. That would have imposed rather significant overhead, both in code complexity and in performance. AFAIK, there is no GUI framework for any environment (though I'm only familiar with Windows GUI frameworks) that implements thread-safe re-entrant code for the main UI thread (and thereby imposes the same requirements on application code), and there are many such frameworks. You could go ahead and call form.SetSomething if you have no concern that the form might be in the middle of some operation -- perhaps caused by the user -- that might cause either SetSomething or the active operation to work incorrectly due to lack of synchronization. The form.Invoke model is rather elegant compared to -- for example -- constructing a raw Windows message (with an application-custom message ID and message format) and calling PostMessage, having modified the window procedure for the form to recognize the message and call the right routine in response. (Most programmers could not take advantage of multi-threading at all before .NET, because of the complexities involved.) If you think of your "worker thread" as being code which could someday be running on a different computer, or inside a different "virtual machine" within the same computer (when the full "utility computing" model has been implemented), the idea of the worker thread saying "please run this code in the form's environment" should make more sense. The reason you can't have a modal message box without another message loop is that the user's actions against a displayed window can't go to that window unless there's a message loop directing messages to that window -- no other message loop will direct messages to a window that it didn't create. (Anyway, does it really make sense to have the worker thread stop dead with a message box while the user is interacting with the main UI? I don't think so. So the main UI should display the message box.) At 09:11 PM 2/22/2004, Jade Burton wrote >As a sidebar to the topic of threads and message pumps, am I the *only* >person in the world who wishes there was greater *cohesion* and >*transparency* between WinForms' and worker threads? > >Why, in 2004, do programmers have to call some hokey >form.Invoke(SetSomeControlMethod, blah) in order to update something on the >form from within a worker thread? > >When I first saw .NET I had hoped that a cleaner model had been adopted by >WinForms, but alas I was disappointed to see it's but another Windows >wrapper. > >I'm not sure there's a clean alternative to having a message pump drive the >UI (maybe there is?), but there *must* be a cleaner way than the current >segregated STA-MTA ideology which has weasled its way into .NET? For >example, why can't I just call form.SetSomeControlMethod and have it update >inline, without any windows messages being sent? (And why can't I create a >modal dialog from within a worker that simply blocks until the user clicks >OK, rather than using another message loop etc?) > >Or are we stuck with what I would regard as a system that requires the >programmer to write (and - ugh - think about) "non-business logic" plumbing >code... > >Jade Burton > >-----Original Message----- >From: Moderated discussion of advanced .NET topics. >[mailto:[EMAIL PROTECTED] Behalf Of Shawn A. Van >Ness >Sent: Saturday, 21 February 2004 10:48 AM >To: [EMAIL PROTECTED] >Subject: Re: [ADVANCED-DOTNET] Thread with message pump (UI thread) > > >Call Application.Run (or even Application.DoEvents) do establish a message >queue for your secondary thread. > >A better answer: You should not be performing any long-blocking operations >on your main UI thread. This rule goes right up there alongside "thread >that creates the window services the window". > >(By "it is difficult to free the main thread" I assume you mean your main >UI thread is performing some long-blocking operation -- like socket i/o, or >calculating pi to 3000 decimal places, or what have you. Don't do that.) > >-Shawn >http://www.windojitsu.com/ > >On Fri, 20 Feb 2004 13:35:57 -0500, Aman Jain <[EMAIL PROTECTED]> wrote: > >>Hi Everybody, >> >>The alarm manager in my Windows Forms application has a alarm control >>(User control) that is used to display errors. >>This is created on the Main thread. Whenever any calls are made on this >>control to display errors, we take care to switch to the Main thread >>(windows principle: thread that creates the window services the window) >>using >> >> >> private void OnAlarmMessageReceived(AlarmMessage msg) >> { >> if(InvokeRequired) // Pass on to GUI thread >> { >> BeginInvoke(new >>AlarmMsgReceivedHandler(OnAlarmMessageReceived), new Object[] { msg } ); >> return; >> } >> // whatever needs to be done >> } >> >>This works fine but with the requirement that the main thread is free. >>Now, there are many situations where it is difficult to free the main >>thread but there are errors that need to be displayed. >>What I need is a UI thread that remains alive during the application >>lifetime on which I can create and service the alarm window. In the >>managed world (using C#) , how do we create a thread with a message pump >>as opposed to a worker thread ? >> >>Any help is greatly appreciated. >> >>Thanks in advance, >>Aman J. Merrill / Analytical Software Corp =================================== This list is hosted by DevelopMentor. http://www.develop.com Some .NET courses you may be interested in: NEW! Guerrilla ASP.NET, 17 May 2004, in Los Angeles http://www.develop.com/courses/gaspdotnetls View archives and manage your subscription(s) at http://discuss.develop.com -- This message has been scanned for viruses and dangerous content by MailScanner, and is believed to be clean. -- This message has been scanned for viruses and dangerous content by MailScanner, and is believed to be clean. =================================== This list is hosted by DevelopMentor. http://www.develop.com Some .NET courses you may be interested in: NEW! Guerrilla ASP.NET, 17 May 2004, in Los Angeles http://www.develop.com/courses/gaspdotnetls View archives and manage your subscription(s) at http://discuss.develop.com =================================== This list is hosted by DevelopMentor. http://www.develop.com Some .NET courses you may be interested in: NEW! Guerrilla ASP.NET, 17 May 2004, in Los Angeles http://www.develop.com/courses/gaspdotnetls View archives and manage your subscription(s) at http://discuss.develop.com -- This message has been scanned for viruses and dangerous content by MailScanner, and is believed to be clean. -- This message has been scanned for viruses and dangerous content by MailScanner, and is believed to be clean. =================================== This list is hosted by DevelopMentor® http://www.develop.com Some .NET courses you may be interested in: NEW! Guerrilla ASP.NET, 17 May 2004, in Los Angeles http://www.develop.com/courses/gaspdotnetls View archives and manage your subscription(s) at http://discuss.develop.com