Fog Creek Software
Discussion Board




Multithreading and message queues

I googled and did not find my answer.  So...

Using Win32 (under Win'CE specifically, but I don't think this matters) I plan to have my worker thread PostMessages to my main GUI thread (parent process) as synchronization to have it update its edit control with data from the buffer which my worker thread has filled.

My issue is, the data will be in chunks (communication app.) and want to assure that it gets pieced together properly for display.  I plan to have each consecutive PostMessage include an index into the buffer queue for which data chunk is to be displayed.  Is there any chance that say: PostMessage(2) can reach the other main thread before PostMessage(1), even though they were sent consecutively in their original order (1 then 2)?  I would find that really weird.  Especially on a single processor machine.

Any experience with this?

sedwo
Wednesday, July 28, 2004

The message queue is a FIFO, so it comes out in the order that it was put in (unless someone explicitly peeks).

Dennis Forbes
Wednesday, July 28, 2004

Well there is the exception of WM_PAINT messages, but apart from them.

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/WinUI/WindowsUserInterface/Windowing/MessagesandMessageQueues/AboutMessagesandMessageQueues.asp

Dennis Forbes
Wednesday, July 28, 2004

Hmmm - why not maintain a data structure so that each message the main window gets tells it to get all available data.

Just guessing, but I think that would give you smoother updating.

.
Wednesday, July 28, 2004

"A common programming error is to assume that the PostMessage function always posts a message. This is not true when the message queue is full. An application should check the return value of the PostMessage function to determine whether the message has been posted and, if it has not been, repost it."

Christopher Wells
Wednesday, July 28, 2004

PostMessage won't change the sequencing, except for WM_PAINT messages.

However, you should have a GUI thread (main), a reader thread and a writer thread (your worker thread) or your GUI may become unresponsive (you clog the GUI thread with your COMM messages which you may be getting 1 per byte).

Instead, the GUI should process GUI messages, the writer should read the COMM, store to a queue buffer and signal the reader (a manual event would suffice; you may have some critical sections when reading/writing on/of the queue) . The reader should wake up when signalled and try and empty the queue buffer while rendering the data on the screen.

In this case the GUI is reponsive because it is not clogged with COMM messages. Any of the reader's updates translate into WM_PAINT messages which have low priority and don't duplicate. Therefore the screen updates will be continous at low comm rates and in bursts at high comm rates.

Dino
Wednesday, July 28, 2004

WM_TIMER messages are also sent to the back of the queue; they're processed just before WM_PAINT is.

Chris Tavares
Wednesday, July 28, 2004

hmmm... interesting.  My design thoughts are:

GLOBAL data buffer: g_DataBuf[256][data_alloc_ptr]

RxThread( worker thread )
{
  ReadFromPort()
  DoDataHandling()
  Insert( g_DataBuf[nextindex] )
  PostMessage( Main, WM_APP+Update_my_edit_control, nextindex )
}


Main( GUI )
{
  case WM_APP+Update_my_edit_control:
      PrintToMyEditControlWindow( g_DataBuf[passedindex] )
      ReleaseMemory( g_DataBuf[passedindex] )
}


This is to aleve my current serious problem of removing any GUI interaction within my worker thread.  Which so happens to cause a deadlock right now. (ya, I know. that's bad)

sedwo
Wednesday, July 28, 2004

CommReaderThread {
    while(true) {
        // move chars from the port into a buffer.
        // best would be a circular queue buffer.
        readFromPort();
        writeToQueueBuffer();
        signalGUIUpdateThread();
    }
}

GUIUpdateThread {
      while(true) {
            waitForSignal();
            resetSignal();

            // when signalled process all there is in the queue.
            while(queueBufferNotEmpty()) {
                  // move chars from the queue buffer into
                  // the GUI buffer.
                  readQueueBuffer();
                  updateGUIBuffer();
            }
            // repaint only once, when done.
            repaintWindow();
      }
}

MainThread {
        while(true) {
              waitForMessages();
              // paint the window out of the GUI buffer.
              if (WM_PAINT) paintFromGUIBuffer();
              // process other messages.
              ...
        }
}

This will give you the double buffering you need. If you're using a control with double buffering you may be able to use the control's buffers instead (you still need 3 threads).

Dino
Wednesday, July 28, 2004

*  Recent Topics

*  Fog Creek Home