Concurrency, part way too many3: Concurrency and Windows


Work's heading up right now, so this one will be briefer than expected.

Windows has its own idea of threading models.  In general, each window on the system is owned by a thread, and that thread is responsible for ensuring that the thread is constantly pumping messages for that window.

This last can cause some real difficulties.  As an example, just recently someone posted on an internal mailing list that they were having problems with their application hanging.

They'd started a really long process on their windows application's main thread, and they wanted to provide feedback to the user.  So they created a new thread, and had the thread put up a progress dialog while the main thread was busy.  They were upset because their dialog box didn't make progress, instead it seemed to get frozen just after coming up.

Raymond immediately came to the rescue with the right answer: The new window was trying to send a WM_SETFOCUS to the old window to tell the old window that it was losing focus, and because the old window's thread wasn't pumping messages, the new window hung.

This is why windows design books keep talking about having a "UI thread" and a "work thread" when designing your applications - it's absolutely critical to keep windows messages pumping on your main thread.

So if your thread ever creates a window, you must pump messages for that window regularly.  The other critical thing to remember is that there are certain functions that require interaction with the windowproc for the window (by calling SendMessage), this is especially true for windows controls (which are typically built from one or more windows).  And there are other functions (like DestroyWindow) that MUST be called from the thread that owns the window.

In general, you can't ever call SendMessage send a message to a window that's owned by another thread (you might get away with it but your chances of deadlocking are pretty high).  There are a couple of ways around this.  First, you could use the GetWindowThreadProcessId API to see if your current thread is the thread that owns the window (this is what the .Net framework "Control.InvokeRequired" method does).  If your thread owns the window, you can simply call SendMessage, if it doesn't, you can post a custom message to the window and do your work on that thread (more-or-less, that's what "Control.Invoke" does under the covers).

Another method is to use the SendNotifyMessage API.  Of course, if you use SendNotifyMessage to send a message to another thread, then then you can't use this API to retrieve information from the destination window (like issuing a WM_GETITEM call).

 

While writing this article, I found an old but still relevant article on MSDN here that describes all of this fairly well.

Edit1: Fixed typo (thanks Ryan).

Edit2: Added comment about DestroyWindow

Comments (7)

  1. Anonymous says:

    ummm should this line "that thread is responsible for ensuring that the thread is constantly pumping messages for that thread" read

    "that thread is responsible for ensuring that the thread is constantly pumping messages for that window"??

    Ryan

  2. Anonymous says:

    We use a thread to read records from a database and inside the thread call sendmessage to let the UI thread know that the records are ready (so it can update it’s display). The reason for using SendMessage is that it causes the data reader thread to block until the UI thread has responded to the SendMessage. We’ve never seen a problem with this code. Is there an issue we should know about?

  3. Anonymous says:

    CSS, as long as there are no interactions between your UI thread and the background thread you should be ok.

    But if your UI thread ever synchronously attempts to get information from the background thread, you might have a problem. Your UI thread would be blocked waiting on the background thread, which would be blocked in SendMessage, waiting on the UI thread.

    Blam.

  4. Anonymous says:

    It is generally safer to use PostMessage, so the UI thread can retrieve data from the worker thread (and possibly enter critical sections) at its leisure.

  5. Anonymous says:

    Anyone that’s really interested in how to do ‘background’ work while keeping the progress in the foreground should check out two things:

    1. Two posts on my blog about it, "Progress Dialogs and Background Tasks" parts 1 and 2: http://blogs.msdn.com/rickbrew/archive/2005/01/28/362876.aspx and http://blogs.msdn.com/rickbrew/archive/2005/02/08/369484.aspx

    2. Paint.NET v2.0’s source code. Head straight for the MainForm.DoEffect() method and also refer to the BackgroundEffectRenderer class. http://www.eecs.wsu.edu/paint.net

    Number 2 is especially interesting because the UI launches a dispatch thread which then launches 2-4 (or more — depends on CPU count) worker threads. We initially ran into trouble because we wanted to preemptively stop and restart this in response to what configuration settings the user changed. So the UI thread would execute Stop(), then Join() … then the dispatch thread would Stop() and Join() all the worker threads … but if one of the threads was in the middle of raising a progress event ("i’m 13% done!") we would dealock because it was calling Invoke() back to the main UI thread. Awful circular deadlock.

    It’s written in C# but the concepts are the same. BeginInvoke() just maps to PostMessage() with a custom window message.

  6. Anonymous says:

    Larry could please comments on some API(s), for example DestroyWindow, requirements to be called only from the thread that created the window.

  7. Anonymous says:

    I could be mistaken but, in .NET the method Application.DoEvents() will keep the message pumps running.

    Any comments?

Skip to main content