February, 2010

  • The Old New Thing

    Microwave popcorn enthusiast proudly proclaims, "I *am* popcorn!"


    Oscar Night is a few weeks away, but when you settle in to watch the show with your bowl of popcorn, please be aware that inhaling deeply from the fumes of a freshly-opened bag of microwave popcorn is not the greatest decision you can make from a health standpoint. (Then again, you probably ought to reconsider eating microwave popcorn in the first place, but let's leave that aside.)

    A disease informally known as popcorn lung afflicts people who work in popcorn factories and has been known since 2002. But in 2007, doctor diagnosed the first case of popcorn lung in an end-user. The risk is not from eating the popcorn but from breathing it. "This patient described enjoying the smell so much he was actually inhaling the steam." The best part of the article was when the patient was asked, "Are you around a lot of popcorn?"

    The response: "I am popcorn."

    Update: Oscar Night is not actually this weekend. That's what happens when you schedule your blog entries over a year in advance and have to guess when Oscar Night is coming.

  • The Old New Thing

    It's fine to use fibers, but everybody has to be on board with the plan


    We saw fibers a long time ago when I looked at how you can use fibers as a form of coroutines to simplify the writing of enumerators. A fiber is a handy tool, but it's a tool with very sharp edges.

    Since fibers are promiscuous with threads, you have to be careful when running code that cares about what thread it is running on, because that code may discover that its thread changed out from under it.

    For example, critical sections and mutexes remember which thread owns them. If you enter a critical section on a fiber, and then you unschedule the fiber, then reschedule it onto a different thread, and then you leave the critical section, your critical section will end up corrupted because you broke the rule that says that a critical section must be exited on the same thread that entered it.

    Actually, you were already in bad shape once you unscheduled the fiber while it owned a resource: An unscheduled fiber cannot release the resource. Unscheduling a fiber is like suspending a thread: Anybody who later waits for that fiber to do anything will be waiting for an awful long time, because the fiber isn't running at all. The difference, though, is that the fiber is unscheduled at controlled points in its execution, so you at least have a chance at suspending it at a safe time if you understand what the fiber is doing.

    For example, suppose you enter a critical section on a fiber, and then unschedule the fiber. Some time later, a thread (either running as a plain thread or a thread which is hosting a fiber) tries to enter the critical section. One of two things can happen:

    1. The thread happens to be the same one that was hosting the fiber that entered the critical section. Since a thread is permitted to re-enter a critical section it had previously acquired, the attempt to enter the critical section succeeds. You now have two chunks of code both running inside the critical section, which is exactly what your critical section was supposed to prevent. Havoc ensues.
    2. The thread happens to be different from the one that was hosting the fiber that entered the critical section. That thread therefore blocks waiting for the critical section to be released. But in order for that to happen, you have to reschedule the owning fiber on its original thread so it can exit its protected region of code and release the critical section.

    More generally, if you use an object which has thread affinity on a fiber, you are pretty much committed to keeping that fiber on that thread until the affinity is broken.

    This affinity can be subtle, because most code was not written with fibers in mind. Any code which calls TlsGetValue has thread affinity, because thread local storage is a per-thread value, not a per-fiber value. (This also applies to moral equivalents to TlsGetValue, like code which calls GetCurrentThreadId and uses it as a lookup key in a table.) You need to use FlsGetValue to get values which follow fibers around. But on the other hand, if the code is not running on a fiber, then you can't call FlsGetValue since there is no fiber to retrieve the value from. This dichotomy means that it's very hard if not impossible to write code that is both thread-safe and fiber-aware if it needs to store data externally on a per-thread/fiber basis. Even if you manage to detect whether you are running on a thread or a fiber and call the appropriate function, if somebody calls ConvertThreadToFiber or ConvertFiberToThread, then the correct location for storing your data changed behind your back.

    If you are calling into code that you do not yourself control, then in the absence of documentation to the contrary, you don't really have enough information to know whether the function is safe to call on a fiber. For example, C runtime functions like strcmp have thread affinity (even though there's nothing obviously threadlike about comparing strings) because they rely on the current thread's locale.

    Bottom line: (similar to the bottom line from last time): You have to understand the code that runs on your fiber, or you may end up accidentally stabbing yourself in the eyeball.

    Bonus chatter: Structured exception handling is fiber-safe since it is stack-based rather than thread-based. Note, however, that when you call ConvertThreadToFiber, any active structured exception handling frames on the thread become part of the fiber.

  • The Old New Thing

    Food products that are offenses against nature: Bagel-fuls


    Wow, it's been a long time since my last rant against food products that are offenses against nature. Today's rant is against Bagel-fuls, a product which Kraft launched in April 2008.

    Bagel-fuls (note the hyphen and the lowercase "f") are a dense, doughy material formed into a log shape, with a cream cheese filling. Think of them as Twinkies, but with cream cheese instead of a sugar cream filling, and with a dense, doughy substance instead of whatever alien material it is they make Twinkies out of.

    The great thing about this product is that it is an attempt by Kraft to learn its lesson from a previous failed bagel-like product: The Philadelphia To Go bagel, a package consisting of a frozen bagel, a one-ounce tub of cream cheese, and a plastic knife. For people who are unable to remember where they kept their cream cheese (hint: the refrigerator) and knives (hint: cutlery drawer).

    Apparently, Kraft's conclusion was not that the product failed because it was too stupid, but rather that it failed because it was not stupid enough.

  • The Old New Thing

    What happens to the fibers which ran on a thread when the thread exits?


    What happens to the fibers which ran on a thread when the thread exits? Are all the fibers destroyed?

    No, only the currently-executing fiber is destroyed. Fibers running on other threads and fibers which are not running on any thread at all are not affected.

    Fibers do not have thread affinity (when not running), and they do not remember what threads they have been run on. Indeed, one of the features of fibers is that you can switch away from a fiber on one thread, then switch to that same fiber on another thread, and that fiber will resume execution on the new thread. Fibers are the social butterflies of scheduling: They will hang out on any thread that invites them to run. Once one thread deschedules a fiber, the fiber loses any affinity for the thread and is perfectly happy to hang out on any other thread. Or on the original thread, if the original thread comes crawling back begging for another chance.

    You can run a fiber on any thread you want, provided you don't run it on two threads at once. (Well, and of course, you have to have prepared the thread for fiber execution by calling ConvertThreadToFiber.)

    Next time, some additional musing about fibers.

  • The Old New Thing

    German language tip: Matratzen = mattresses, Matrosen = sailors


    Be careful not to confuse the two.

    Since we're sharing: During a conversation in German, I talked about seeing Unfall (accident) instead of Abfall (garbage) on the street. To my credit, I immediately corrected my error. To my discredit, the error was made at the state finals of a German language contest.

  • The Old New Thing

    Why does the CBS_SORT combo box style sort the left square bracket so strangely?


    Some time ago, Michael Kaplan asked (and answered), How the @#%&*! does CBS_SORT choose to sort it all out? One detail in his answer is that the sorting algorithm used by CBS_SORT is basically CompareString, with special treatment for the left square bracket U+005B.

    Why is the left square bracket so special?

    It goes back to the LB_DIR message (which is in turn used by DlgDirList, CB_DIR, DlgDirListComboBox, and related functions). If you ask for drives to be added to the list or combo box, they are added in the form [-X-], where X is the drive letter. The left square bracket is special-cased so that the drive letters sort to the top of the list.

    Of course, LB_DIR and related functions and messages are pretty old-school nowadays, but the code for them is still around, so the sort function still needs to worry about them.

  • The Old New Thing

    Le Chatelier's principle in action: Announcements


    As I noted some time ago, one of the most important lessons I learned from Systemantics is Le Chatelier's Principle for complex systems which states, "Every complex system resists its proper functioning."

    At Microsoft, there are processes galore. For example, when a server is taken down for planned maintenance, you can expect a series of messages, perhaps following this pattern:

    • Server X will be unavailable from time A to time B. (Sent a few days before the planned outage.)
    • Server X will be unavailable today from time A to time B.
    • Server X is going down now. It should be back at time B.
    • Server X is back.

    The problem with this is that you often receive notifications for servers you have no interest in, indeed whose mere existence you were previously entirely unaware of. The notification messages don't include instructions on how to stop receiving the notifications, or if they do, the instructions are incorrect (no points for guessing how I discovered this), so people set up email rules to auto-delete the notifications instead of trying to figure out how to unsubscribe.

    The result is that we now have a system in place which generates large quantities of email which are automatically deleted.

  • The Old New Thing

    On the Internet, everybody wants to know if you're a dog


    On Slate, Michael Agger expounds on increasing pressure for people to provide pictures of themselves online. I've managed to resist so far.

    That article also tipped me off to a phenomenon I didn't even know had a name: MySpace angles.

  • The Old New Thing

    Custom navigation in dialog boxes, redux


    SuperBK asks, "What's the proper way to add keyboard support to a dialog box?"

    There are many options available to you. The most traditional way is to pick them off in the dialog loop, either hard-coding the keys in code or putting them into resources by moving them to an accelerator resource. Moving them to an accelerator resource is a good idea if the keys are subject to translation (for example, if they are mnemonic). On the other hand, picking them off in code is your only choice if the action you want to take cannot be mapped to a WM_COMMAND message (or if you simply don't feel like creating such a mapping).

    SuperBK appears to be using MFC, a framework I have only cursory familiarity with, so I'll accept that the MFC way of customizing the dialog loop is to use PreTranslateMessage.

    One issue that was raised was the case where a keyboard accelerator is active only when a certain window has keyboard focus. But if that's your design, then you don't need to mess with the dialog loop at all. For example, the space bar pushes a button, but only if focus is on the button. There is no special code in the dialog loop to accomplish this; it's just part of the button control's WM_KEYDOWN message handler.

    This is one of those cases where you discovered a hammer and start seeing everything as a nail. When the user presses a key, the keyboard message is posted to the window that has keyboard focus. You don't have to do any special work to pick it off, because it'll get to that window anyway if you just leave it alone.

    In SuperBK's specific example, the list box should behave a certain way if it has focus and the user hits VK_RETURN. Okay, well, VK_RETURN is a special keyboard navigation key for dialog boxes, so you need to tell the dialog manager, "No, I want this key to go to me." Just have the control return DLGC_WANTMESSAGE in response to WM_GETDLGCODE if the message is a press of the VK_RETURN key. The dialog manager will let the message go through to the window, and then the window can perform its custom VK_RETURN action.

  • The Old New Thing

    How many servings are there in a single-serve cup? The answer might surprise you


    I was in the grocery store, and there was a sign advertising a new product.

    Delight in a cup
    Your favorite XYZ Ice Cream
    Now in convenient single-serve cups.

    I took a look at the cup. Seemed kind of big for a single serving. I picked one up to read the nutritional information.

    Servings per container: 2
Page 1 of 4 (35 items) 1234