Re: Multithreading problem: losing message ptr after a PostThreadMessage() to a UI thread

From: Joseph M. Newcomer (newcomer_at_flounder.com)
Date: 04/05/04


Date: Mon, 05 Apr 2004 15:41:00 -0400

Not surprising. You should not be using PostThreadMessage to a thread that is not known to
have a message pump. Until you know the thread has actually gotten as far as its initial
PeekMessage/GetMessage sequence, you cannot reliably post a message to it.

What I do is have the OnIdle handler test a boolean (initialized to FALSE), and if it is
not set, it does a PostMessage to the main UI thread to indicate that it has started (by
the time OnIdle is called, the message queue exists). I then set the boolean to TRUE to
indicate I've sent the notification. The main GUI thread, when it receives the message,
knows the UI thread is now ready to accept communication and can do a PostThreadMessage to
it and know it will be received.

Otherwise, the thread has no message queue and PostThreadMessgae merely discards the
message.

On 5 Apr 2004 11:32:17 -0700, Patel_Hetal@msn.com (Hetal) wrote:

>Hey All,
>
>Ive created a UI thread by deriving a class from CWinThread. After I
>get a reference to the Thread Object from AfxBeginThread, I do a
>PostThreadMessage using a user defined message map.
>
>In the thread class, I am getting my handler function to run, meaning
>the message was received. However Im also passing a character array
>thru wparam. In message handler function wparam is null, and thus am
>not able to get my data! Any idea why this is happening. The memory
>was initially allocated on the heap.
>
>Below is some sample code from my project:
>
>// Class declaration
>const UINT WM_SN_LLC_MSG2 = WM_APP + 10;
>class CTestMsgPump : public CWinThread
>{
> DECLARE_DYNCREATE(CTestMsgPump)
>protected:
> CTestMsgPump(); // protected constructor used by dynamic
>creation
>
>......
>public:
> afx_msg LRESULT OnRecvMessage(WPARAM wp, LPARAM lp);
>
>...
> DECLARE_MESSAGE_MAP()
>};
>
>// defnition Class
>IMPLEMENT_DYNCREATE(CTestMsgPump, CWinThread)
>CTestMsgPump::CTestMsgPump()
>{
>}
>
>CTestMsgPump::~CTestMsgPump()
>{
>}
>
>.....
>BEGIN_MESSAGE_MAP(CTestMsgPump, CWinThread)
> ON_MESSAGE(WM_SN_LLC_MSG2, OnRecvMessage)
>END_MESSAGE_MAP()
>...
>
>LRESULT CTestMsgPump::OnRecvMessage(WPARAM wp, LPARAM lp)
>{
> char* pchMsg;
> pchMsg = (char*)wp; //***** wp is NULL !!! **** PROBLEM
> return 0;
>}
>
>// Main / Calling thread
>
> CRuntimeClass* ptrMsgPump = RUNTIME_CLASS( CTestMsgPump );
> pThreadpump1 = AfxBeginThread(ptrMsgPump);
>
> DWORD dwThreadID = pThreadpump1->m_nThreadID;
> UINT wmMsg = WM_SN_LLC_MSG2;
>
> char * pchMessage = new char[100];
> wParam = (WPARAM)pchMessage;
*****
The thread is almost certainly not yet running, has no message queue, so the
PostThreadMessage is guaranteed to fail
****
>
> bRet = ::PostThreadMessage(dwThreadID, wParam, lParam, 0);
> // until message queue is initialized
****
This is meaningless. Why do you think Sleep(0) is going to do anything useful? It won't,
and it won't guarantee that the thread is running. Bottom line: if you have to add a
Sleep() call to make your threading system work, it doesn't, won't, and can't be made to
unless it gets a redesign.
****
> for(int nIndex = 0; (nIndex < 10 && !bRet); nIndex++)
> {
> Sleep(0);
> bRet = ::PostThreadMessage(dwThreadID, wmMsg, 0, 0);
> }
>
>Has anyone seen something like this below ? I have no idea whats
>happening here.
****
Key here is to stop thinking sequentially. You are thinking sequentially, and that is why
it fails. You are thinking because you have created the thread, a PostThreadMessage will
work. It doesn't, it won't, and unless you build a positive-acknowledgement protocol like
I described, it cannot be made to work reliably, or possibly even at all.
****
>thanks,
>Hetal.

Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm



Relevant Pages

  • Re: CAsyncsocket derived class being run as a thread
    ... PostThreadMessage may or may not work correctly. ... there must be a message queue in the receiving thread. ... What does a message pump do? ... >is completed, the code is executing in a new context, not that when you ...
    (microsoft.public.vc.mfc)
  • Re: CAsyncsocket derived class being run as a thread
    ... has a message queue, and it won't have a message queue until it issues a GetMessage, ... PostThreadMessage ... >>>is completed, the code is executing in a new context, not that when you ... Joseph M. Newcomer [MVP] ...
    (microsoft.public.vc.mfc)
  • Re: CAsyncsocket derived class being run as a thread
    ... PostThreadMessage may or may not work correctly. ... There are two variants, threads with message pumps and threads without message pumps, erroneously called "UI threads" and "worker threads". ... It retrieves messages from the thread's message queue and dispatches them. ... is completed, the code is executing in a new context, not that when you called CreateThread, so all the normal caveats apply. ...
    (microsoft.public.vc.mfc)
  • Re: User thread problem
    ... >functionality using one thread instead of two. ... Did you read the documentation I posted which talked about PostThreadMessage ... failing if the target thread doesn't have a message queue? ...
    (microsoft.public.vc.mfc)
  • Re: Multithreading problem: losing message ptr after a PostThreadMessage() to a UI thread
    ... get created on the first call to PostThreadMessage which returns true. ... > The thread is almost certainly not yet running, has no message queue, so the ... > PostThreadMessage is guaranteed to fail ... > and it won't guarantee that the thread is running. ...
    (microsoft.public.vc.mfc)