Date: | October 18, 2007 / year-entry #382 |
Tags: | code |
Orig Link: | https://blogs.msdn.microsoft.com/oldnewthing/20071018-00/?p=24743 |
Comments: | 53 |
Summary: | At the end of the day, there's a window handle in there. As we saw a few years ago, windows have thread affinity. You can push work to a background thread all you want, but once you send a message to the window (or do something that results in a message being sent to the... |
At the end of the day, there's a window handle in there. As we saw a few years ago, windows have thread affinity. You can push work to a background thread all you want, but once you send a message to the window (or do something that results in a message being sent to the window), you've given control to the UI thread. Since the shell is all about user interfaces, the shell naturally expects that all threads that use it are single-threaded apartments. Historically, however, you sort of got away with violating this rule because older versions of the shell used their own custom fake version of COM rather than using the official one in As the shell gradually switched to using real COM instead of fake COM, and as new features were added to the shell which relied more and more heavily on callers following the rules for apartment threading, programs that had skirted the rules started running into problems. If you got away with it on earlier versions of Windows and the problem was severe, there was a good chance the shell would have to do some re-architecting to allow your dodgy code to keep working. A member of the COM team explained that COM assumes fundamentally that multi-threaded apartments are UI-free. No UI means no need to pump messages. If you initialize COM in MTA mode on a thread, you'd better not do any UI or your thread will stop responding to messages whenever COM needs to talk to another thread. |
Comments (53)
Comments are closed. |
Any chance of disrupting the blog post queue and telling us whose fault is this?
http://blogs.zdnet.com/hardware/?p=829
It looks like it has to do with shell…
Fascinating… I love this sort of insight. Thanks, Raymond!
Oh how I wish that conventions and standards were adhered to, forcing poor quality third-party code to improve instead of festering through OS rearchitecture.
@Igor
I am not sure what you want more than what is already known: There is a memory leak in ole32.dll when handling files with Extended attributes, and it happens that this AV software puts EAs on every single file it traces… So you end up with your memory exhausted. That plus there already is a hotfix for it! what more do you need ?
Never mind, even though it is an OLE issue, it is in shell32.dll
Here is the link for the hotfix:
http://support.microsoft.com/kb/942435/en-us
It’s good that such vital information is located in small KB article instead of MSDN chapter dedicated to COM.
Also it’s good that MSDN location referenced from this KB is ‘Location Cannot Be Found’.
Even better sounds ‘own custom fake version of COM’!
I agree with Pink Duck. You can only hack your way around so many compatibility issues before it starts to get unmanageable.
On the other hand, I guess we can’t leave those Lotus Notes 1.0 users out in the dark on Windows 2045.
@Bahbar:
What more do I want? I want to know how this kind of error got into the OS which "was written from the ground up for stability, security and performance"?
I would expect that in 2007 file operations are 100% reliable.
Sorry for the offtopic (which perhaps has something to do with Raymond’s post after all, who knows).
"What more do I want? I want to know how this kind of error got into the OS which "was written from the ground up for stability, security and performance"?"
If you think about it for a moment you’ll notice that a ground-up rewriting would in fact imply the creation of more bugs initially as it is new code.
Ignoring that fact, the coders are human and they make mistakes (just like a certain post bashing an MS product off-topic for no reason).
@Kemp:
Then don’t say you did it from the ground up if you didn’t. That could be considered false advertisement.
About coders are human, I know because I am a developer myself, but this kind of error should’ve never got past beta testing.
By the way I wasn’t bashing any product.
Raymond said: “Suggestions for future topics go into the suggestion box when it reopens.”
I know Raymnod, but I am afraid I won’t live long enough to submit it, much less read the response knowing how much suggestions you were getting :)
If your email worked I would have emailed the link to you instead of asking here. Sorry again for the offtopic.
"Then don’t say you did it from the ground up if you didn’t. That could be considered false advertisement."
I didn’t say it was a lie. I said that if the claim was true then it should follow that there would be new and exciting bugs. As you pointed out, there are in fact new and exciting bugs =P
If a system has critical flaws the design is to blame. A single bug should not be able to cause a critical flaw.
I suggest the suggestion box should open soon.
"I suggest the suggestion box should open soon."
Your suggestion will be added to the back of the queue =P
Thursday, October 18, 2007 1:15 PM by Igor
I want to know how this kind of error got into the OS which "was written from the ground up for stability, security and performance"
We all know that’s a lie. Look at the very topic of this blog entry: Even the UI is singlethreaded.
Thursday, October 18, 2007 3:20 PM by Suggester
I suggest the suggestion box should open soon.
I second this.
poochner: the freezing you’re seeing is unlikely to be a result of single-threaded UI work.
Raymond is only saying that each window is single-threaded, as it is in every other windowing environment. Every process obviously has its own thread(s), so every process’ UI is independent of every other process.
Do not confuse this with Win16 where every task ran on the same thread, making the whole system single-threaded.
I have yet to meet a UI framework where the UI components were not inherently single-threaded. The Java Swing library explicitly creates interfaces to handle passing messages to the UI thread or for executing code within the UI thread. Bad things happen on the Macintosh when you attempt to use multiple threads to manage components within the same application. And X Lib, as I recall (though it has been many years) is also intrinsically single-threaded as well. Hell, even Mac System 7’s cooperative threading model could still get you into trouble in the UI if you weren’t careful.
I think it stems from the model we use for UI programming, of an event pump which handles incoming messages and dispatches them accordingly. If you have multiple message pumps it’s just too easy to "cross the streams".
Far easier to adopt the model that a single thread is responsible for all UI operations in a standard application, and use some system of message passing from background task threads to the UI thread.
I think BeOS had a threaded UI. If they could do it, why not others?
Thursday, October 18, 2007 4:06 PM by Bill Woody
I have yet to meet a UI framework where the UI components were not inherently single-threaded.
I think that in 2007, and in the age of multicore and multicpu, this should finally change. As such I’m personally working on a multithreaded UI model. The gist of it is that each component can either be in one of two states, "active" or "idle", and changes states when user input is received. A thread is created when the component goes active, and it’s destroyed once it goes idle again.
Sorry for going off topic.
@Igor
If you’re a regular reader here you’ll know that this is the wrong place to discuss this stuff. At this point you’re just trolling.
I can think of many examples where allowing multi-threaded changes to the UI would result in race conditions and other nasty problems.
I can only think of a handful of cases where it would be both useful and sensible to allow it, and in all of those cases it still doesn’t seem worth it since it is not difficult to route all your messages to the UI thread.
When I first started UI programming I used to think it sucked that I couldn’t change/update UI elements from any thread but now that I’m more experienced I think that would’ve resulted in a big mess and I don’t see a lot of benefit from being able to do it. Seems like a solution looking for a problem, to me.
I do wish that COM and message queues in general were not so tied together, and also that they were completely separate from the windowing system, and also that COM only had one threading model — free threading, and let each component serialise calls or add usage restrictions as appropriate to it — but there’s nothing we can do about any of that now without a time machine (or an abstraction layer that hides it all from us) (or a completely new OS, but I quite like running all my existing apps).
UI frameworks have one UI thread because (drumroll…) they have to draw one image on one screen. Sure, you could let several threads draw, but have fun when your window frame repaints itself out of order and your buttons disappear.
You could add synchronization calls (which people forget to use) and have threads peek at each other’s data to find out what their draw order is, but it would just be a roundabout way of getting the same result that a single thread provides relatively cheap.
There’s a well-known paper by Lauer & Needham on this subject, that everyone ought to read.
Leo Davidson: It’s your decision, race conditions or a hung UI. I personally would prefer the latter.
With regard to the poster who commented about "Java Swing library explicitly creates interfaces to handle passing messages to the UI thread or for executing code within the UI thread", the issue is all to do with locks. GUI events "bubble down" (for example, a keydown event is fired, followed by a keypress, followed by an input event, followed by any user actions) and each stage needs it’s own locks and moniters. It turned out (at least for Swing) that having proper thread safety in a GUI environment is an almost impossible task; unless you confine all GUI activities to one thread (as Swing has done)
Perhaps this explains why my 2K* system gets "stunned" for a second or so at random intervals. It’s irritating because I notice it most when I’m playing StarCraft** but it happens at other times, as well.
*never got around to upgrading the OS. It has 2GB of mem, though.
**Ok, I’m just old-school.
"I would expect that in 2007 file operations are 100% reliable."
That sounds like a great idea. Any suggestions on how to achieve that lofty goal? Despite what you might believe, it’s not a "solved problem". There are some *very good* theoretical solutions, *some* of which have been implemented, to varying degrees of accuracy and bug-free-ness.
Offhand, I can’t think of *any* operations in computation that are 100% reliable. Software is hard, people (and systems) are imperfect, bugs are (apparently) inevitable. We all do our best and get over it.
Well, most of us get over it.
@meh:
And if you are regular here, then you know I don’t give a damn about anonymous poster’s opinions. If you have a name use it to support what you say with it. Otherwise either quit complaining or get lost.
“they have to draw one image on one screen. Sure, you could let several threads draw, but have fun when your window frame repaints itself out of order and your buttons disappear.”
Argh….
Why not let them draw each into their own screen and then use compositing to merge only parts that have changed based on UI element Z order?
I can’t believe I had to write that!
Raymond, I know. I was saying that it would be possible to solve that and still have threaded UI.
[ .. One thread draws a black line, and another draws a green rectangle, and the two overlap and the results are random. .. ]
You divide the screen area into rectangles that can’t overlap, and each a thread is created whenever a rectangle receives user input, that thread updates the visible state of the rectangle, processes the input, and then quits. Multithreaded UI minus the races.
[If it’s that easy, why do so many people mess it up? -Raymond]
It "isn’t that easy". Win32 user interface work is inherently singlethreaded. It would require implementing some impossible function that sorts out all the hundreds of window messages that win32 uses, and asynchronously dispatching them to the right hwnd.
[And people complain that Windows programming is too hard. I know, let’s fix that by making it even harder still! -Raymond]
The current USER32 implementation is not only hard to use, but susceptible to hung UIs. The multithreaded UI would be still decently hard to use, but would always be responsive.
I personally would prefer the former **. I should learn to proof-read my posts.
"It’s your decision, race conditions or a hung UI. I personally would prefer the former."
(Edit streamlined in)
You don’t *have* to hang your UI, you just need to follow basic principles of doing it right…
Additionally, a programming error causing a hung GUI is much easier to debug than one causing race conditions.
"You don’t *have* to hang your UI, you just need to follow basic principles of doing it right…"
If you do it right, of course everything will work perfectly. Doing it right is doing it asynchronously, which (For synchronous APIs) usually requires firing up another thread anyway. Which is what I’m suggesting the UI do automatically. I’m trying to make it easier to do it correctly, which is the entire point of having an abtraction in the first place. To make it easy to avoid things like this: http://blogs.technet.com/markrussinovich/archive/2005/08/28/the-case-of-the-intermittent-and-annoying-explorer-hangs.aspx
As a user what I like about multi-core processors is that even if one program is maxing out a core at 100% I still have another core available for other programs.
All the multiple thread UI people here seemdetermined to nix that, despite many viewing it as the single most important hardware innovation in the last five years.
"Why not let them draw each into their own screen and then use compositing to merge only parts that have changed based on UI element Z order?"
Erm, that’s such a great idea, that’s exactly how it already works! Simply replace the word "screen" with the phrase "top-level window" and you’re done.
@Igor – The BeOS UI may have been multithreaded, but it was also horribly ugly and un-customizable.
[If it’s that easy, why do so many people mess it up? -Raymond]
@Triangle – that was sarcasm.
For everyone complaining about single-threaded UIs – if multi-threaded UI design worked as well as you seem to think it would, most operating systems and programming languages would be using it. They aren’t, and I’m sure you can figure out why.
Back On Topic, I believe that the point that Raymond is making – once again – is that if you put in the time and effort to follow the rules, instead of using hacks and workarounds to get the job done quickly, you won’t have problems further down the line. The rules are there for a reason…
Great idea Triangle, except… nobody said the effect of an input event was limited to one screen tile.
Although compositing may yet be parallelized, I don’t see the same happening in the way events are handled.
The suggestion box will probably be closed again when it gets to the front of the queue!
@The_Assimilator:
Those are the things that are fixed easily once you have more important things (like threading in this case) working.
Raymond, I know that people complain it is hard, but you shouldn’t make it easier by ruling out better and more efficient ways to do something just because some simpleton can’t get it quickly or at all.
I remember when I first faced Windows programming, numerous other programmers tried to scare me with messages, pumps, etc saying how hard Windows UI programming is.
I was already familiar with the messaging concept back from the good old Amiga days so I asked them "What exactly is hard here?" and started coding.
Truth is that you have a bunch of programmers with no previous experience in UI programming. They will always complain that it is hard, regardless of what you throw at them.
MFC and WTL were attempts at simplifying UI programming for the masses. If say WTL was at the OS UI core, and if the only way to write UI applications was through deriving from WTL classes, things would be vastly different now.
If you have some spare time, I recommend you to skim through a book "Programming the Be Operating System" by Dan Parks Sydow (ISBN 1-56592-467-3) if you manage to find a copy.
"As a user what I like about multi-core processors is that even if one program is maxing out a core at 100% I still have another core available for other programs.
All the multiple thread UI people here seemdetermined to nix that, despite many viewing it as the single most important hardware innovation in the last five years."
Just smile and nod your head.
"Oh Stephen you’re SO smart".
So you don’t mind Adobe announcing "All your Cores are us".
Now when Acrobat Reader takes up 100% processor time I still play minesweeper. It’s a question of priorities.
I wish you had written this post a month ago, Raymond.
I think using COM places a lot of responsibility on the developer and it’s really easy to mess up:
http://inside.echobit.net/archives/2007/09/27/mfc-and-com/
Granted, if you make an honest effort to understand how COM works under the hood, many mistakes could be avoided. I just keep finding my knowledge of COM lacking…
I’ve never found UI programming all that difficult. That’s probably because I’ve been doing multi-threaded event-driven programming for more than 20 years. That wasn’t GUI programming, but it was data comm. The more things change, the more they stay the same. People get excited about 64-bit programming, but that’s nothing new at all. I worked on those in the mid-1980s. What’s new is availability. Does it take up an entire house, or sit beside your desk? Personally, I like the new environments.
I checked and StarCraft runs under Windows 95 or 98. It’s likely 16-bit.
So the answer is simple for a COM server, if you are going to have UI on that thread, initialize it as a STA, otherwise initialize it as a MTA, otherwise calls to that thread will hang because that thread is not pumping messages because it has no UI.
The people arguing for multi-threaded UI IMHO are trying to find solutions for problems that aren’t there.
When you draw UI, the commands are batched and put in a queue, and then drawn by the graphic cards, for example with OpenGL, in a different thread. There is only one graphic card, and it can only do one thing at a time.
Splitting the screen in quaters and updating each part in different thread is riduculous because
1) there is only one graphic card. remember?
2) who says the entire screen needs to be redrawn?
3) who says the bottleneck is the actual drawing, and that splitting it up on processors is the best thing to do?
4) who says the work required to draw each part of the screen is equal?
Having single threaded UI is a good thing that makes sense. It’s up to the apps to decide how to split the work on multiple-CPUs to make the best part of it. For example, photoshop can split all the image rendering onto multiple CPUs and then at the end make a single ‘bitblt’ on screen. That ‘bitblt’ isn’t the bottleneck! It may not even be using the CPU.
btw, about BeOS: IMHO this OS lives in the real of fantasy. We’re told the UI was ‘fully threaded’. Which everyone’s said that about their product. It doesn’t mean that it’s what you think it means. You’re fantasizing about what that means! Easy to do when no one knows for sure and it’s not around to disprove!
The drawing could have been all serialized in one thread, while each window could have have lived in its own thread. That’s the same thing as running multiple apps in any operating system. Saying the Windows UI is single-threaded means that the input events and the drawing is serialized for each process, it doesn’t mean that there are no thread in the OS!
ulric: I think you misunderstood something here; a multithreaded UI wouldn’t releave bottleneck, and yes it might actually exacerbate a few, but having a singlethreaded UI means that one unresponsive button can lock the entire system. And, if you’ve ever used Windows, you’ve experienced explorer randomly locking up for a few minutes, and I bet you’ve been pissed off by it.
In Win32 you can create windows in different threads, in fact each processes run in different threads already, and do not "hang the entier system". This blog entry doesn’t say that Windows doesn’t support creating and managing windows in different threads, because it does, it describes explorer.exe how it interacts with COM.
I’ve responded to your suggestion of ‘dividing the screen in tiles’, it doesn’t prevent your "hung button" because it’s not waiting for the redraw code anyway.
From your other suggestion, I don’t think you want the OS to create threads on all messages just ‘in case’ the app may do something that takes time, it’s expensive to create threads, and unnecessary for 99% of the cases. If you need this in your app, you can do it, only you know what’s appropriate and safe, what data structures are synchronized properly. Creating a thread on user action like mouse down at the toolkit level isn’t good because, beside being expensive, the input message returns before the work is done so you get synchronization issues that make programming even more complex. You’d easily end up with multiple threads running concurrently, stepping over each other, and race conditions. UI out of synch with what’s going on Only your own app can know what it needs.
Absolutely, Windows Explorer sometimes partially locks up on network timeout on WAN — for example I’ve seen the task bar wait for a Run command (but in my experience other Explorer windows were not locking up in my case). This is entirely fixable in Explorer, it’s not a flaw inherent to the input UI messages and drawing being treated in one thread. For network access they should start a second thread and have a progress bar to tell us what the heck the system is doing when it’s taking long, and have a damn cancel button. Conversely notice as well the cases where in doesn’t happen. It’s definitely not totally single-thread. Try Finder on OS X to see how more multi-threaded Explorer is :)
A lot of people have this view. However, they are completely wrong.
Your problem is that the OS thread scheduler is not doing what you want. It’s particularly bad in Windows, which uses a terrible scheme (boosting thread’s priority, both based on user input and pseudo-randomly, IIRC) – what you want is a decrease of the priority of CPU-eating threads, as implemented in basically every other OS, where 100% CPU usage is usually not noticeable from the UI (until you request something that does need lots of CPU cycles).
You can sort of get around this by manually decreasing the priority of the offending process (or thread, if you have the right tools). Ideally applications would automatically do this (IE did with the address autocompletion IIRC) but then you’d be at a disadvantage against the bad mannered guys, so it’d be better if it was a thread scheduler policy.
A nice feature would be throttling so even a thread which wants CPU continuously would run less than 100% of the time. There are some third party apps that fake this by pausing and unpausing threads at a fast rate.
Sunday, October 21, 2007 11:46 PM by ulric
I’ve responded to your suggestion of ‘dividing the screen in tiles’, it doesn’t prevent your "hung button" because it’s not waiting for the redraw code anyway.
You responded with four statements that don’t actually discredit my suggestion:
1) there is only one graphic card. remember?
http://en.wikipedia.org/wiki/Scalable_Link_Interface
and, even your cheapest graphics card nowadays has at least 4-8 pixel fill pipelines
2) who says the entire screen needs to be redrawn?
Nobody.
3) who says the bottleneck is the actual drawing, and that splitting it up on processors is the best thing to do?
It probably isn’t.
4) who says the work required to draw each part of the screen is equal?
Nobody.
Of course a control that does alot of processing or a blocking operation will become unresponsive. And its busyness would be apparent in that it wasn’t responding. But the rest of the interface shouldn’t become unresponsive. As it stands, with Windows, it does.
"In Win32 you can create windows in different threads, in fact each processes run in different threads already, and do not ‘hang the entier system’"
If Explorer hangs, then the taskbar hangs, and, effectively, the system has hung.
That’s a bug with explorer specifically, not with single-threaded user interfaces in general.
Here’s a question for you: in a multi-threaded UI, how would you handle key-up events being processed before key-down events?
“Here’s a question for you: in a multi-threaded UI, how would you handle key-up events being processed before key-down events?”
The key down event is held pending until the control is ready to process it. I think this is the part most people here are misunderstanding: The multithreaded UI I’m suggesting is exactly like how Windows works now, except that a seperate message loop is maintained for each control instead of just for each window, and that the GetMessage(&msg, …) ; TranslateMessage(&msg, …); DispatchMessage(&msg); in the message loop is done by the window manager instead of the thread that created the window.
Ulric said: “There is only one graphic card, and it can only do one thing at a time.”
That is a lame assumption on your part. There are systems with as much as 3 video cards. In DirectX 10.1 video cards will support context switching meaning they will be able to interact with more than one thread at once.
Ulric said: “btw, about BeOS: IMHO this OS lives in the real of fantasy”
I won’t comment this. I just suggest you to download a copy (it is free) and try it.
Ulric said: “Saying the Windows UI is single-threaded”
But it is single-threaded!
Insert a DVD and immediately double-click on My Computer icon and you will see it for yourself. First you will get Explorer window with an empty gray pane. Then the whole window goes white failing to repaint itself for several seconds. Even if your intent was to navigate to the DVD content it is annoying, not to mention if you needed to check something else on your HDD.
With a hardware this powerfull, non-responsive UI which fails to repaint is unforgiveable regardless of what you believe to be the cause.
In my opinion, current UI is flawed at least in the sense that it is polling applications for changes. We all know that polling is not efficient.
Raymond said: “I think you’re confusing Windows with one specific Windows program.”
For roughly 90% of the users out there (for whom I was speaking because I personally know better) Explorer _is_ Windows.
That is why they are pissed with it so much. They don’t view it as a separate application, but rather as an integral part of the OS.
My point was that even if you replace Explorer completely (and frankly I haven’t seen such a replacement yet — note that in my book it would have to do without leaning on shell32.dll to be considered a replacement), you will most likely end up having same issues with UI as Exlporer does. My bet is that the problem is with window manager.
To me it is totally stupid to do it like this:
WM: do you have something to paint?
AP: no
WM: do you have something to paint?
AP: nope
WM: do you have something to paint?
AP: sigh, I already told you I don’t
WM: this window overlapped you, repaint
AP: but why, I haven’t changed anything?
Messaging and event driven programming is one thing, it is ok to get messages when something happens like when user presses a key — this is polling and it is bad. It just creates or at least increases the chances for hanging the UI redraw if the application isn’t written correctly.