Thread affinity of user interface objects, part 2: Device contexts


Last time, we discussed briefly the thread affinity rules that govern window handles.

Device contexts (DCs) also have a certain degree of thread affinity. The thread that calls functions such as GetDC must also be the one that calls ReleaseDC, but as with window handles, during the lifetime of the DC, any thread can use it. If you choose to use a DC in a multi-threaded manner, it's your responsibility to coordinate the consumers of that device context so that only one thread uses it at a time. For example, to host windowless controls across multiple threads, the host obtains a DC on the host thread, then asks each control in sequence to draw itself into that DC. Only one control draws into the DC at a time, even if the control happens to be on a different thread.

The thread affinity of DCs is much more subtle than that of window handles, because if you mess up and release a DC from the wrong thread, things will still seem to be running okay, but the window manager's internal bookkeeping will be messed up and you may get a bad DC from GetDC a little later down the line.

Next time, the remaining user interface elements.

Comments (9)
  1. Anonymous says:

    "the consumers of that device context"

    I have done many things with a DC, some even stupid, but I don’t think I’ve ever consumed one. Is there some undocumented GdiEntry4711BonApetit(HDC) added now to do this? :-)

    Perhaps… "use" is more descriptive?

  2. Anonymous says:

    "Consumes" implies to me that you have just depleted the supply of something. So I guess you could say that creating a DC "consumes" a device handle. But I can’t see how /using/ that handle would deplete anything, except opaque resources "behind the scenes".

  3. Anonymous says:

    > The thread that calls functions such as

    > GetDC must also be the one that calls

    > ReleaseDC,

    Sorry to multicontext this thread, but I tried to figure out how to figure out whether it’s necessary to call ReleaseDC in the first place, and I couldn’t figure it out.

    MSDN page

    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_mfc_CWnd.3a3a.GetDC.asp

    says:

    > Unless the device context belongs to a

    > window class, the ReleaseDC member function

    > must be called to release the context after

    > painting.

    So some CWnd objects have device contexts that belong to window classes and some CWnd objects have device contexts that don’t belong to window classes? How can I figure out which CWnd objects[*] are really CWnd and which are really CNonWnd?

    The same MSDN page answers Mike and TC:

    > Since only five common device contexts are

    > available at any given time, failure to

    > release a device context can prevent other

    > applications from accessing a device context.

    It makes me wonder though. If I’m using a terminal server and suddenly can’t see my screen, should I whack some of my neighbours until at most four of them remain?

    [* Of course this usually involves subclasses of CWnd, i.e. derived and more specialized types.]

  4. Anonymous says:

    So some CWnd objects have device contexts that belong to window classes and

    >some CWnd objects have device contexts that don’t belong to window classes?

    >How can I figure out which CWnd objects[*] are really CWnd and which are really CNonWnd?

    There’s a window class style called CS_OWNDC which if set means the window has a permanent DC. So what the docs mean is that when working with windows created of a class with CS_OWNDC you don’t need to call ReleaseDC().

    I think it’s harmless to call ReleaseDC() even on the DC from windows of a CS_OWNDC class, so best to always call it (correct me if I’m wrong someone).

  5. Anonymous says:

    So… you have to free the DC from the same thread that allocated it, and also the system sort-of-crashes when you free the DC from the wrong thread.

    Now I know this is over-simplistic but is it too much fuzz to add a "creator thread" to the DC and then just plainly refuse to free if it doesn’t match? Or else, at least tell us all the gory details about why it isn’t done ;)

    ps. Your earlier article about double ctrl-alt-del already saved a friend of mine who just added a new user to his XP system and lost the admin option, so… thanks!!!

  6. Answering "why it isn’t done" is a topic too large for a comment. It goes to philosophical issues that controlled API design in the 1980’s. More coming later this month.

  7. Anonymous says:

    Wednesday, October 12, 2005 11:18 AM by SJ

    > when working with windows created of a class

    > with CS_OWNDC you don’t need to call

    > ReleaseDC().

    OK, and I can tell an object of an MFC class derived from CWnd to tell me what its Windows style is. Thank you.

    > I think it’s harmless to call ReleaseDC()

    > even on the DC from windows of a CS_OWNDC

    > class, so best to always call it (correct me

    > if I’m wrong someone).

    Even better news. Although it looks like you were guessing, Mr. Chen posted later and he didn’t correct you, so it looks like you’re right. Thank you.

    Now if that MSDN page would be revised to say that it’s always safe to call ReleaseDC() even in cases where the MSDN reader doesn’t know how to figure out whether it’s necessary…

  8. "he didn’t correct you, so it looks like you’re right"

    Do not assume my silence implies consent. Do you expect me to fact-check every single statement made in a comment? If you do, then I’ll just disable comments.

  9. Anonymous says:

    Thursday, October 13, 2005 1:56 AM by oldnewthing

    > Do not assume my silence implies consent.

    OK, I understand not to assume.

    > Do you expect me to fact-check every single

    > statement made in a comment?

    "Expect" as in "I think you’re supposed to do it"? No. "Expect" as in "I see you do it frequently"? Well yes…

    > If you do, then I’ll just disable comments.

    You know how much MSDN benefits from that policy. (Yes I know MSDN is older and no one had the idea of blog-style or wiki-style posting of corrections, and that isn’t MSDN’s fault. Nonetheless you know MSDN’s quality problems and you know how much better it is to allow corrections and discussions.)

Comments are closed.