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

Date:October 11, 2005 / year-entry #300
Tags:code
Orig Link:https://blogs.msdn.microsoft.com/oldnewthing/20051011-10/?p=33823
Comments:    9
Summary: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...

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. Mike 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. TC 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. Norman Diamond 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. SJ 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. Antonio 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. Norman Diamond 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. Norman Diamond 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.


*DISCLAIMER: I DO NOT OWN THIS CONTENT. If you are the owner and would like it removed, please contact me. The content herein is an archived reproduction of entries from Raymond Chen's "Old New Thing" Blog (most recent link is here). It may have slight formatting modifications for consistency and to improve readability.

WHY DID I DUPLICATE THIS CONTENT HERE? Let me first say this site has never had anything to sell and has never shown ads of any kind. I have nothing monetarily to gain by duplicating content here. Because I had made my own local copy of this content throughout the years, for ease of using tools like grep, I decided to put it online after I discovered some of the original content previously and publicly available, had disappeared approximately early to mid 2019. At the same time, I present the content in an easily accessible theme-agnostic way.

The information provided by Raymond's blog is, for all practical purposes, more authoritative on Windows Development than Microsoft's own MSDN documentation and should be considered supplemental reading to that documentation. The wealth of missing details provided by this blog that Microsoft could not or did not document about Windows over the years is vital enough, many would agree an online "backup" of these details is a necessary endeavor. Specifics include:

<-- Back to Old New Thing Archive Index