1

I know that in order to access the UI controls from another thread, I should use PostMessage(). However, PostMessage() is asynchronous, so for example if I try to change the text of an "EDIT" control, I will not be able to delete the text buffer when finished because I do not know when the window procedure will finish processing the message.

So these are two ideas I can think of to access the UI controls from another thread:

  • Create a user-defined message, for example, I send to the UI thread something like: "insert these 200 rows (all stored in one string, delimited by '\n' or something) into ListViewX", and when the UI thread receives this message, it updates ListViewX, and when done, it deletes the string (which is allocated on the heap).
  • The other approach is to place the code that accesses the UI control inside of a function, and send the function pointer to the UI thread, which will then call it.

Does one of these approaches provide some advantages over the other, and are there other approaches to do this?

4
  • If it is acceptable for the thread to block until the UI thread has processed the message, SendMessage is another option. Commented Apr 11, 2015 at 7:23
  • @Harry Johnston I have read that SendMessage() could cause a deadlock (which is not always easy to predict). See: flounder.com/workerthreads.htm, the section: Worker threads and the GUI II: Don't touch the GUI. Commented Apr 11, 2015 at 7:29
  • 1
    I disagree with that article's interpretation of the problem. The deadlock occurred because the GUI thread was waiting for a worker thread to complete, and implemented the wait in such a way that GUI messages were not being processed in the meantime. You shouldn't do that, because even if you don't deadlock, the GUI will be frozen until the worker thread completes. Disclaimer: I am not expert at GUI programming. Commented Apr 11, 2015 at 7:32
  • Yes i believe waiting on UI thread is a bad programming practice.I had some of the wort experiences at work when i started programming due to this . Commented Apr 11, 2015 at 7:38

2 Answers 2

3

I frequently use the following pattern (the arrows indicate a "uses" relationship):

           +---------------+                     
           | Communication |        +-----------+
      +--->+  Data Object  +<---+---+ Thread #0 |
      |    | (thread safe) |    |   +-----------+
      |    +---------------+    +---+ Thread #1 |
      |                         |   +-----------+
      |                         |     ...        
+-----+----+                    |   +-----------+
| Main (UI)|                    +---+ Thread N  |
|  Thread  |                        +-----------+
+----------+                                     

The Communication Data object is threadsafe and typically ref-counted (important for non-GC-languages). The object provides a couple of typical methods (all optional, depending on the actual use case):

  • work item queue
  • data getter/setter for any other data that needs to be exchanged
  • progress information to be visualized in the UI
  • an abort/status flag, combined with ...
  • waitable event object to signal various things

Because the data object fully takes care of itself, including synchronizing access to its data, and more or less automatic cleanup due to ref-counting, you end up with all that thread stuff nicely encapsulated into one dedicated class. I found this very handy in various situations.

Furthermore, the approach fully decouples the worker threads from the UI, so the threads don't even know whether or not there is an UI at all and how it looks like: is it a GUI? Is it a CLI? A web service maybe? Last not least it keeps the UI responsive, because the UI thread (or the equivalent thereof) can fully decide on its own when and how often to update the UI.


PS: Probably there's an official GOF name for it, don't know.

Sign up to request clarification or add additional context in comments.

2 Comments

Just pointing out a distinction between two approaches: one way is that the worker thread blocks until the request has made it to the main UI thread and back again; and the other is a "fire and forget" where the communication object would be a thread-safe FIFO or a Windows Message that doesn't expect a response
It's not a FIFO per se. It can be anything you want, including a FIFO, but not limited to it. The single most important point here is about decoupling, in particular the worker threads have no knowledge about the UI. Imagine you want to use that piece of code in a server application, e.g. a web service. There is no HWND to SendMessage() to. But since we decoupled the whole thing you just need to write the part from the thread that would be the UI thread in a desktop application, plus there is no blocking wait involved anywhere.
2

I know that in order to access the UI controls from another thread, I should use PostMessage(). However, PostMessage() is asynchronous, so for example if I try to change the text of an "EDIT" control, I will not be able to delete the text buffer when finished because I do not know when the window procedure will finish processing the message.

You are mistaken. There is no compulsion to use PostMessage. And indeed for setting the window text of a control, you should not use PostMessage. You need to send WM_SETTEXT synchronously, for the very reasons you outline. If you don't send it synchronously then you don't know when to destroy the text buffer.

What you need to do is as follows:

  • If the window is in your process, then you should use SetWindowText.
  • If the window is in a different process, then you should use SendMessageTimeout to send the WM_SETTEXT message.

For windows in a different process, SetWindowText is documented not to work. It's a little more complex than that, as Raymond explains, but you still, as a rule, should not use it on a window in a different process. So, for windows in a different process, use SendMessageTimeout to send WM_SETTEXT. The timeout is to prevent your application become hung if the target application is hung.

6 Comments

"f you don't send it synchronously then you don't know when to destroy the text buffer" I am using PostMessage() to send a user-defined message and not to send WM_SETTEXT, and in the UI thread I call SendMessage() with WM_SETTEXT and when SendMessage() returns I destroy the text buffer.
"I am using PostMessage() to send a user-defined message" - fine, as long as the message params do not involve pointers that need cleanup. If that is the case, you have the same problem again, only with a different message ID. PostMessage() is asynchronous which raises the problem of who cleans up when. And what if the window is gone and nobody receives the message ever? Memory leaks? That's a hard to manage and maintain, and prone to error. I wouldn't do that.
@JensG I am sending a pointer to the buffer in the user-defined message, and then I call SendMessage() from the UI thread and then I delete the buffer when SendMessage() returns. I don't understand how this can't work! As for the Window is destroyed before the message is handled, this will not happen, as I am sending the user-defined messages to the main window (so the only way it is destroyed is if the application is closed).
Note that I did not say "it will never work". I said "it is hard to maintain and prone to error", especially all error edge cases. At the end it is your choice.
@JensG The thing is I don't see how it is prone to error. BTW I got this idea from here: flounder.com/workerthreads.htm, see the section: Worker threads and the GUI II: Don't touch the GUI.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.