Thread affinity of user interface objects, part 1: Window handles

Date:October 10, 2005 / year-entry #299
Tags:code
Orig Link:https://blogs.msdn.microsoft.com/oldnewthing/20051010-09/?p=33843
Comments:    7
Summary:Different objects have different thread affinity rules, but the underlying principles come from 16-bit Windows. The most important user interface element is of course the window. Window objects have thread affinity. The thread that creates a window is the one with which the window has an inseparable relationship. Informally, one says that the thread "owns"...

Different objects have different thread affinity rules, but the underlying principles come from 16-bit Windows.

The most important user interface element is of course the window. Window objects have thread affinity. The thread that creates a window is the one with which the window has an inseparable relationship. Informally, one says that the thread "owns" the window. Messages are dispatched to a window procedure only on the thread that owns it, and generally speaking, modifications to a window should be made only from the thread that owns it. Although the window manager permits any thread to access such things as window properties, styles, and other attributes such as the window procedure, and such accesses are thread safe from the window manager's point of view, load-modify-write sequences should typically be restricted to the owner thread. Otherwise you run into race conditions such as the following:

wpOld = (WNDPROC)GetWindowLongPtr(hwnd, GWLP_WNDPROC);
SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)newWndProc);

LRESULT CALLBACK newWndProc(...)
{
 ... CallWindowProc(wpOld, ...); ...
}

If modifications to the window procedure are made carelessly from any thread, then between the first two lines, a second thread may change the window procedure of the window, resulting in newWndProc passing the wrong "previous" window procedure to CallWindowProc.

Why, then, does Windows even allow a non-owner thread from changing the window procedure in the first place? Because, as we all know, 16-bit Windows was a co-operatively multi-tasked system, which means that one thread could do anything it wanted secure in the knowledge that no other thread would interrupt it until it explicitly relinquished control of the CPU. Therefore, the above code sequence was safe in 16-bit Windows. And for compatibility reasons, the code continues to be legal, even though it isn't safe any more. (Note, however, that in an attempt to limit the scope of the damage, the window manager allows only threads in the process that owns the window to change the window procedure. This is a reasonable limitation since separate address spaces mean that function addresses in other processes are meaningless in the process that owns the window anyway.)

Next time, a look at device contexts.


Comments (7)
  1. Jack Mathews says:

    This is a great counter argument to your points about punching holes in virtual machines, and this is exactly the "screen door" I was talking about.

  2. Could you be more specific what "this" is? Are you saying that one of the holes punched in the virtual machine would be unifying the window lists and supporting subclassing across VMs?

  3. Jack Mathews says:

    "This" means the safety problems introduced in the Window Manager.

    I suppose, thinking it through, this is more the problem of Win32 being pretty close to code compatible with Win16 and less about VM’s. Even a simple function, like getting the size of text in a window caption and then getting that text, can cause you to get incorrect results depending on thread scheduling. These are fixable problems.

    I guess my real issue is still the thought that Win16 and Win32 should exist as two happy families living side by side code-wise. But I’ve beaten that to death already.

    (The problem I mention above is calling GetWindowTextLength(), then a thread makes the caption longer, then calling GetWindowText passing the text length from GetWindowTextLength will result in a truncated version of that longer string)

  4. Sean Bryant says:

    Does this also apply to the new subclassing functions? SetWindowSubclass, GetWindowSubclass?

  5. sandman says:

    <quote>

    Therefore, the above code sequence was safe in 16-bit Windows. And for compatibility reasons, the code continues to be legal, even though it isn’t safe any more.

    </quote>

    My, that is a strange definition of compatible.

    So, a program which was safe can now exihibt undefined behaviour as opposed to ellicting an error message!

    Surely window should invoke some sort of modal warning then in this case (non-owner thread modifing a window) .

    You could have a bunch of compaitblity flags removing this on an application basis, or if certain locks were held.

  6. No, an old program that was safe is still safe. But a new program is not safe. Think about it.

  7. Multi-threaded apartments do not pump messages.

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