Date: | March 16, 2006 / year-entry #98 |
Tags: | code |
Orig Link: | https://blogs.msdn.microsoft.com/oldnewthing/20060316-12/?p=31883 |
Comments: | 23 |
Summary: | Many people have noticed that the animation bar control in version 6 of the common controls no longer uses a background thread to draw the animation. Instead, it acts as if the ACS_TIMER style is always set, even if the caller didn't pass it. Why is that? The first reason is that the background thread... |
Many people have noticed that the animation bar control in version 6 of the common controls no longer uses a background thread to draw the animation. Instead, it acts as if the The first reason is that the background thread didn't actually help any. In order to draw transparent animations, the painting loop needs to query the animation control's parent to obtain the background color, and that query entails sending a message to the main UI thread. Consequently, the main UI thread must remain responsive to messages in order for the animation to render properly. If the main UI thread stopped responding to messages, the Therefore, the UI thread had to remain responsive to messages. And if that's the case, then there's no need for the background thread after all. The UI thread can just run a timer and draw the frames in response to the timer message. The second reason for getting rid of the background thread is that it actually made things worse. Another thread means more context switches and more memory pressure, since the additional thread needs a stack and other supporting data structures. Admittedly, this is a comparatively weak reason. The third reason is that using a background thread for painting simply encouraged bad code. Using a background thread for painting meant that the UI thread could stop responding to messages for long periods of time and usually get away with it because the query for the background color comes early in the animation cycle when the main UI thread most likely has not yet gotten into the part of the long-running procedure that stops responding to messages. As a result, the background thread encouraged programs to stop pumping messages on UI threads because "it seems to work fine". The result is programs that fail to maintain a responsive UI, resulting in periodic mysterious hangs in the window manager when another program tries to broadcast a message and gets wedged up behind the unresponsive window. This leads to increased frustration for the end user and a general feeling that "Windows sucks". By making the suckage obvious, programmers will be more likely to notice that they are doing something bad and do something to address it. Masking the problem with a background animation thread merely allows the problem to persist. |
Comments (23)
Comments are closed. |
Interesting. That seems to me like the sort of strategy that people here are always recommending you take (break stuff visibly), as opposed to the sort of strategy you normally do take (bend over backwards to keep stuff working even if they’re doing it wrong). Is there actually a slight shift in policy there, or am I seeing shadows where none exist?
I’m running IE 6 on Windows XP SP2. I notice that when IE is auto-detecting my proxy settings, the Windows logo animation (top-right) freezes at whatever point it is.
Is this a manifestation of the same case you’ve mentioned here?
Agree with what Scott has pointed out. In the short term, the bending over backwards helps. In the long time though, it merely encourages bad practices.
The idea is that you should animate in your message pump thread and do blocking activities in a separate worker thread. The animate control made it seem like you should do blocking activities in your message pump thread and animate in a separate worker thread.
The old way not only made it easy to implement the wrong behavior, it encouraged it. And the worst part of it is that it could make it seem like your app was working (because the animation is running) while the rest of Windows would lock up (because it was waiting for yoru app to finish blocking).
Why not just begin drawing the animation on a background thread using a default background colour and simultaneously send an asynchronous request for the true background colour?
Granted, this may involve 3 threads in total, but hey, we’re in >2Ghz machines nowadays and the context switch overhead is minimal compared to the time it takes to click the mouse.
RichB, We’re in >2Ghz machines certainly but if i have learnt something since i started working in computing is that it is absolutly necesary to save resources wathever it is possible.
Is the timer less accurate than the thread?
Isn’t Vista moving things in the opposite direction? I noticed the controls have fancy animations such as the progress bar and seem to run regardless of how unresponsive the host program is.
I’m on < 1GHz
I think the difference in this case is that making the bug obvious doesn’t actually break any code. The app still works, it just doesn’t look as good.
Mike Dunn: More likely, the difference is here that old apps don’t use version 6 of the common controls, they get stuck with version 5. You have to make a manifest to get them to use v6 (i.e. developer does it), in which case there isn’t a binary backwards compatibility issue.
I noticed that many animations now no longer run smoothly. For example, when emptying the Deleted Items folder in Outlook 2003, the animation performs poorly and sometimes appears to hang. Even in Explorer, the animations sometimes get stuck before they continue.
The change may have increased the stability of applications, but it impaired the visual quality and smoothness of many animations.
>Windows often just sits there like nothing
>happened, then the Start button, etc, become
>unresponsive, and then finally, the app launches
>and everything I just did to the Start bar
>happens in fast motion?
I’ve seen that a *LOT*! If something /really/ bad happens then after a while when you move the mouse the pc speaker gives a clicking noise while moving.
PatriotB: Doesn’t that make the balloon look a bit "drunk" in the first place? (lagging behind the parent window a bit as you drag it around)
But the UI freeze is indeed strange. Does it still happen when you turn off acceleration in the display properties?
>Windows often just sits there like nothing
>happened, then the Start button, etc, become
>unresponsive, and then finally, the app launches
>and everything I just did to the Start bar
>happens in fast motion?
That used to happen all the time for me but seems to happen less since SP2 was released. I believe it’s related to DDE.
>I’ve seen that a *LOT*! If something /really/
>bad happens then after a while when you move
>the mouse the pc speaker gives a clicking
>noise while moving.
This type of thing is a totally separate issue from the "explorer freezes" issue. I’ve seen this happen a few times too–often the system becomes unusable and you have to restart. I actually encountered this the other day in a program I was writing: I have a tracking balloon tooltip, which would adjust its position whenever the parent window moves (i.e. in response to WM_MOVE). Well, minimizing the window (and thus moving the window to -32000,-32000) causes the entire UI to soon freeze (sometimes with the aforementioned beeping), leaving no exit but a restart. I’m using XP SP2, ComCtl32 6; haven’t tested it on other platforms.
So previous versions of the Animate *did* use a background thread to do painting? Hmmm, I always thought that worker threads weren’t supposed to touch UI objects? Must admit I do have written a component that does painting in a secondary thread, and it works, but I always assumed it was illegal. Is it perhaps?
When programmers do something bad or sucky, the operating system should
(a) Cover up for it
(b) Make the suckage as obvious as possible
There are good arguments in the abstract for both positions, and you’d have to look at each actual case to see which is best for that particular case…
But I’ve got to believe it’s a mistake to change from (a) to (b) between versions. Whatever happened to backwards compatibility?
8 – The lag is hardly noticable, at least on my 2 GHz computer, but it is there. It’s not a big deal for my app, though.
I didn’t try with turning acceleration off. As a workaround, I now hide the balloon when the app is minimized (Couldn’t rely on WM_SIZE — that’s too late and it still froze; needed to listen for WM_SYSCOMMAND). The bug must have something to do with the -32000 thing: right after the main window is minimized (and moved to -32000,-32000), the balloon gets repositioned to the upper left corner (it always has to stay within the desktop, apparently). The problem may be it trying to draw the "stem" all the way back to -32000… No idea why it would cause the entire OS to freeze; must be some kind of bug in the kernel portions of GDI/User.
Can anyone point me to a description how to create a manifest for a simple vc6-app?
PingBack from http://blogs.msdn.com/oldnewthing/archive/2007/02/14/1676656.aspx