• The Old New Thing

    Does Windows have a limit of 2000 threads per process?


    Often I see people asking why they can't create more than around 2000 threads in a process. The reason is not that there is any particular limit inherent in Windows. Rather, the programmer failed to take into account the amount of address space each thread uses.

    A thread consists of some memory in kernel mode (kernel stacks and object management), some memory in user mode (the thread environment block, thread-local storage, that sort of thing), plus its stack. (Or stacks if you're on an Itanium system.)

    Usually, the limiting factor is the stack size.

    #include <stdio.h>
    #include <windows.h>
    DWORD CALLBACK ThreadProc(void*)
     return 0;
    int __cdecl main(int argc, const char* argv[])
    int i;
     for (i = 0; i < 100000; i++) {
      DWORD id;
      HANDLE h = CreateThread(NULL, 0, ThreadProc, NULL, 0, &id);
      if (!h) break;
     printf("Created %d threads\n", i);
     return 0;

    This program will typically print a value around 2000 for the number of threads.

    Why does it give up at around 2000?

    Because the default stack size assigned by the linker is 1MB, and 2000 stacks times 1MB per stack equals around 2GB, which is how much address space is available to user-mode programs.

    You can try to squeeze more threads into your process by reducing your stack size, which can be done either by tweaking linker options or manually overriding the stack size passed to the CreateThread functions as described in MSDN.

      HANDLE h = CreateThread(NULL, 4096, ThreadProc, NULL,
                   STACK_SIZE_PARAM_IS_A_RESERVATION, &id);

    With this change, I was able to squeak in around 13000 threads. While that's certainly better than 2000, it's short of the naive expectation of 500,000 threads. (A thread is using 4KB of stack in 2GB address space.) But you're forgetting the other overhead. Address space allocation granularity is 64KB, so each thread's stack occupies 64KB of address space even if only 4KB of it is used. Plus of course you don't have free reign over all 2GB of the address space; there are system DLLs and other things occupying it.

    But the real question that is raised whenever somebody asks, "What's the maximum number of threads that a process can create?" is "Why are you creating so many threads that this even becomes an issue?"

    The "one thread per client" model is well-known not to scale beyond a dozen clients or so. If you're going to be handling more than that many clients simultaneously, you should move to a model where instead of dedicating a thread to a client, you instead allocate an object. (Someday I'll muse on the duality between threads and objects.) Windows provides I/O completion ports and a thread pool to help you convert from a thread-based model to a work-item-based model.

    Note that fibers do not help much here, because a fiber has a stack, and it is the address space required by the stack that is the limiting factor nearly all of the time.

  • The Old New Thing

    On paying for your meal upon leaving a restaurant


    Robert Scoble's embarrassment over forgetting to pay a restaurant bill reminds me of an even more embarrassing incident experienced by a component team from the Windows 95 team.

    To celebrate something or other, their team went to lunch at The Salish Lodge, a fine dining establishment. At the end of the meal, everybody thought somebody else was going to handle the bill, and they all walked out as a group. The administrative assistant who made the reservation received a somewhat concerned telephone call from the restaurant when they discovered that a large party just skipped the check. Profuse apologies were extended and the bill was settled over the phone (with what I assume was a very generous tip). I just happened to be in the hallway when this whole thing happened and got to hear the story from the very exasperated administrative assistant shortly after it transpired.

    So remember, folks: Pay the bill before leaving the restaurant. It saves everybody a lot of grief.

  • The Old New Thing

    Watching the game of "Telephone" play out on the Internet


    Let's see if I can get this straight.

    First, Chris Pirillo says (timecode 37:59) he's not entirely pleased with the word "podcast" in Episode 11 of This Week in Tech. The Seattle-PI then reports that the sentiment is shared with "several Microsoft employees" who have coined the word "blogcast" to replace it. Next, c|net picks up the story and says that the word "podcast" is a "faux-pas" on Microsoft campus. [Typo fixed: 9am]

    In this manner, a remark by someone who isn't even a Microsoft employee becomes, through rumor, speculation, and wild extrapolation, a word-ban at Microsoft.

    Pretty neat trick.

  • The Old New Thing

    When Marketing edits your PDC talk description


    A few years ago, I told a story of how Marketing messed up a bunch of PDC slides by "helpfully" expanding acronyms... into the wrong phrases. Today I got to see Marketing's handiwork again, as they edited my talk description. (Oh, and psst, Marketing folks, you might want to link to the full list of PDC sessions from your Conference Tracks and Sessions page. Unless, of course, y'know, you don't want people to know about it.)

    For one thing, they stuck my name into the description of the talk, thereby drawing attention to me rather than putting the focus on the actual talk topic. Because I'm not there to be me. I'm there to give a talk. If I were just there to be me, the title would be "Raymond Chen reads the newspaper for an hour while listening to music on his headphones."

    (That's why I don't do interviews. Interviews are about the interviewee, and I don't want to talk about me. People should care about the technology, not the people behind it.)

    They also trimmed my topic list but stopped before the punch line.

    ... asynchronous input queues, the hazards of attaching thread input, and other tricks and traps ...

    The punch line was "... and how it happens without your knowledge." After all, you don't care about the fine details of a feature you don't use. The point is that it's happening behind your back so you'd better know about it because you're using it whether you realize it or not.

    They also took out the reference to finger puppets.

  • The Old New Thing

    The best book on ActiveX programming ever written


    I was introduced to the glory that is the world of Mr. Bunny many years ago. Mr. Bunny's Guide to ActiveX is probably the best book on ActiveX programming ever written.

    If you haven't figured it out by now, it's a humor book, but it's the sort of madcap insane geek humor that has enough truth in it to make you laugh more.

    My favorite is the first exercise from the first chapter: Connect the dots. (Warning: It's harder than it looks!)

  • The Old New Thing

    How can I recover the dialog resource ID from a dialog window handle?


    Occasionally, I see someone ask a question like the following.

    I have the handle to a dialog window. How can I get the original dialog resource ID that the dialog was created from?

    As we saw in our in-depth discussion of how dialogs are created from dialog templates, the dialog template itself is not saved anywhere. The purpose of a template is to act as the... well... "template" for creating a dialog box. Once the dialog box has been created, there is no need for the template any more. Consequently, there is no reason why the system should remember it.

    Besides, if the dialog were created from a runtime-generated template, saving the original parameters would leave pointers to freed memory. Furthermore, the code that created the dialog box almost certainly modified the dialog box during its WM_INITDIALOG message processing (filling list boxes with data, maybe enabling or disabling some buttons), so the dialog box you see on screen doesn't correspond to a template anywhere.

    It's like asking, "Given a plate of food, how do I recover the original cookbook and page number for the recipe?" By doing a chemical analysis of the food, you might be able to recover "a" recipe, but there is nothing in the food itself that says, "I came from The Joy of Cooking, page 253."

  • The Old New Thing

    Why isn't Windows Setup just a disk reimage plus a registry dump?


    Why can't all the registry key needed by Windows Setup be precomputed and splorted at one go? One reason is that Windows Setup can be customized via a so-called "unattend file", which means that a lot of the work cannot be precalculated. Some settings also have cascade effects on other settings.

    Also, the model for component registration is to make each component responsible for its own registration, which can in turn be context-sensitive: "If the system has configuration x, then do y else z". Internet Explorer's component registration for example contains many conditional sections based on the installation configuration specified in the unattend file and the even fancier Winbom.ini file used by Sysprep-based deployment (which is used by computer manufacturers and large corporations).

    Making each component responsible for its own registration reduces entanglements between components but also means that "global optimizations" such as precalculating the registry cannot be done. Engineering is about tradeoffs and this is one of them: Maintainability vs. speed.

    (Of course, there are sections of the registry that are not context-sensitive, and those to some degree have already been gathered together for block copying onto the machine during Windows Setup. Look at the HIVExxx.INF files on your Windows XP CD.)

    That said, it appears that Longhorn setup is moving towards the "disk image" model. I wish them luck.

  • The Old New Thing

    Why do Microsoft code samples tend to use ZeroMemory instead of { 0 }?


    If you go browsing around MSDN, you'll find that code samples tend to call ZeroMemory explicitly rather than using "= { 0 }" notation. Why is that?

    To make it clearer for people who are used to other programming languages.

    Like it or not, a significant percentage of people who write programs for Windows do it in languages other than C and C++. Although those developers may have a basic understanding of C and C++, they don't have all the language subtleties memorized.

    Compare the situation of speaking in English to a group of people where not everyone speaks the language fluently. If you're considerate of your audience, you're going to avoid the more esoteric grammatical constructions, the rare words, and the obscure idioms. Instead of saying, "Were it to rain, we will see that umbrellas be available," you would use the simpler "If it rains, then we will make sure that umbrellas are available," thereby avoiding the grammatical complexity of the implied conditional by inversion ("if"), the subjunctive of condition ("were"), the implied conclusion ("then"), and the subjunction of intention ("be").

    Heck, even people who claim to know C and C++ don't have all the language subtleties memorized. Some of them have false impressions of what " = { 0 }" does. And who among us really has C/C++'s bizarre operator precedence rules committed to memory?

    Consequently, MSDN samples tend to use ZeroMemory to make it blindingly obvious what is being set to zero. One of the things we've learned over the years is that many people just copy/paste sample code without understanding it. If there are little things like ZeroMemory that can be done to make the intent of sample code clearer and reduce translation errors, then that's a good thing.

    If you prefer " = { 0 }", then go ahead and use it, secure in the knowledge that thousands of programmers aren't going to read your code and try to translate it into Visual Basic because that's the only language they know. But MSDN doesn't have that luxury.

  • The Old New Thing

    I'll see (some of) you in Los Angeles in September


    Jeremy Mazner has asked me to put together a 400-level session at this year's PDC. I came up with the title "Five(ish) things every Win32 developer should know (but likely doesn't)". Of course, now I have to think of five things! Here are some ideas I've been kicking around.

    • The memory scene: Physical address space != physical memory != virtual memory != virtual address space
    • Consequences of the way CPUs work: How my O(n) algorithm can run circles around your O(log n) algorithm; why much of what you learned in school simply doesn't matter
    • Parent vs. owner windows
    • Asynchronous input queues, the hazards of attaching thread input, and how it happens without your knowledge
    • Dialog units, DPI and the overloaded term "large fonts"

    Would you go to a talk that covered these topics? If not, what topics would you rather hear me talk about?

    Follow-up: The talk will be a little over an hour. (And fixed the title. Thanks, Dave.)

  • The Old New Thing

    Google is the cute two-year-old girl with curly blond hair that gets all the attention


    Let's see, Google Maps adds the world outside the United States, Canada and the UK, and people go ga-ga. Nevermind that Google's new "maps" have nothing beyond country boundaries. "Aww, look at Google, she's so cute and adorable!"

    I'm sure the people at the existing online map services like MapQuest and MSN MapPoint are sitting there like older siblings, wondering when exactly they turned into chopped liver. MSN MapPoint has actual maps of most of Europe, and MapQuest's library of maps is larger still. (Kathmandu anyone?) Both sites provide documentation on how to link directly to them. Yet they don't get drooled over.

    Somebody at MapQuest should take out a full page ad that goes something like this:

    Dear Google Maps,

    Welcome to the rest of the world! If you ever need driving directions, don't hesitate to ask.

    Love ever,

Page 81 of 93 (930 items) «7980818283»