views:

27

answers:

2

I have a main program that creates the threads in order: ThreadB then ThreadA (which is passed ThreadB's ID) using the CreateThread function.

Thread A sends a message to Thread B using PostThreadMessage. B gets the message using GetMessage.

The problem I am having is that PostThreadMessage blocks randomly the first time it is called and never returns, some times the program funs fine, other times I run the program and it blocks with 0 CPU usage at the first postthreadmessage. However if I add Sleep(10) to ThreadA before the first PostThreadMessage, I never seem to encouter this problem.

What am I missing about the timing of threads and messages?

+3  A: 

You cannot send a message to a thread until it has a message queue. Message queues are not created until that thread calls a function such as GetMessage or PeekMessage. What your sleep does is delay the sending thread long enough that the receiving thread has called GetMessage and set up its message queue.

Incidentally, I strongly recommend against using PostThreadMessage as the messages can get lost. It is better to create a message-only window (with a parent of HWND_MESSAGE) on the receiving thread and send messages to that instead.

Anthony Williams
+1  A: 

To add to Anthony Williams correct answer, the code I use to deal with this looks like. I have a class similar to MyThread...

void MyThread::Start()
{
  m_hResumeMain = CreateEvent(NULL,FALSE,FALSE,NULL);
  m_hThread = CreateThread(NULL,0,ThreadProc,this,0,&m_dwThreadId);
  WaitForSingleObject(m_hResumeMain,INFINITE);
  CloseHandle(m_hResumeMain);
  m_hResumeMain=0;
}

DWORD MyThread::ThreadProc(LPVOID pv)
{
  MyThread* self = (MyThread*)pv;
  return self->ThreadProc();
}

DWORD MyThread::ThreadProc()
{
   MSG msg;
  // Create the thread message queue
  PeekMessage(&msg,0,0,0,PM_NOREMOVE);
  // Resume the main thread
  SetEvent(m_hResumeMain);
  while(GetMessage(&msg,0,0,0)>0){
    if(msg.hwnd){
      TranslateMessage(&msg);
      DispatchMessage(&msg);
    }
    else {
     DoThreadMessage(&msg);
    }
  }
  return 0;
}

The crux of the issue is you ultimately cannot rely on a Sleep to guarantee that the worker thread is sufficiently initialized. Plus, in general there is usually some mimimal amount of work a worker thread needs to have done before the launching thread should be allowed to resume. So create an event object before creating the thread, wait for it on the main thread and signal it on the worker thread once the initialization is done.

Chris Becke