Click to See Complete Forum and Search --> : Sending Messages between threads


DumbMonkey
August 23rd, 2005, 06:53 AM
Hi,
I have several classes which are instantiated several times in a static library file. They send messages up to other classes, which manipulate them and then they get sent up to the parent window. Initially I was using postthreadmessage (yeah i know) and peekmessage in the library class threads. This resulted in dropped messages because postthreadmessage is totally useless (nice one Microsoft). The highest class uses PostMessage to send to the parent window, using the window handle which works fine, but messages are getting dropped in the class threads. The question is, what is the best was to send messages between these threads? Do i create dummy windows and use wndprocs, to allow me to use PostMessage? This seems like a fudged way to do it. I could use sockets, but again its kind of fudged.
Any help would be greatly appreciated. Thanks.

humptydumpty
August 23rd, 2005, 07:23 AM
Hi,
I have several classes which are instantiated several times in a static library file. They send messages up to other classes, which manipulate them and then they get sent up to the parent window. Initially I was using postthreadmessage (yeah i know) and peekmessage in the library class threads. This resulted in dropped messages because postthreadmessage is totally useless (nice one Microsoft). The highest class uses PostMessage to send to the parent window, using the window handle which works fine, but messages are getting dropped in the class threads. The question is, what is the best was to send messages between these threads? Do i create dummy windows and use wndprocs, to allow me to use PostMessage? This seems like a fudged way to do it. I could use sockets, but again its kind of fudged.
Any help would be greatly appreciated. Thanks.

just use SendMessage and perform your work that's all you have to do.
here pParent is a Object of your Main Class in which your Thread is Running
pParent->m_ProgressDlg.SendMessage(WM_DESTROY,0,0);

like

static unsigned long __stdcall FnSendThread(LPVOID lpParam)
{
CSend *pParent = (CSend *)lpParam;
HRESULT hr = NULL;
pParent->m_ProgressDlg.SendMessage(WM_DESTROY,0,0);
return S_OK;
}

DumbMonkey
August 23rd, 2005, 07:41 AM
Many thanks for your help. What i Have is this-

In main app-

CMyDevice : CDevice
{
VOID CreateThread();
DWORD WINAPI ProcessThreadHandler(CMyDevice *MyDevice);
...
}

DWORD WINAPI CMyDevice::ProcessThreadHandler(CMyDevice *MyDevice)
{
while (!MyDevice->KillThread)
{
if (PeekMessage(&Msg,NULL,0,0,PM_REMOVE))
{
...
<Build Message>
PostMessage(MyhWnd ...);
}
}
}

Then in lib file -

class CDevice
{
VOID CreateThread();
DWORD WINAPI ProcessThreadHandler(CDevice *Device);
CSerial *Serial;
}

DWORD WINAPI CDevice::ProcessThreadHandler(CDevice *Device)
{
while (!Device->KillThread)
{
if (PeekMessage(&Msg,NULL,0,0,PM_REMOVE))
{
...
<Build message>
PostThreadMessage(MyDeviceHandle ...)
}
}
}

class CSerial
{
...
}

VOID CSerial::Post(CHAR Var)
{
PostThreadMessage(DeviceHandle, Var ... )
}

There is actually another class in between the two which does some other message formatting. Can I use your approach to replace all of these stupid postthreadmessage/peekmessage functions in the lower classes?
Again, thanks for your time.

MikeAThon
August 23rd, 2005, 09:36 PM
I would recommend against the use of SendMessage between threads. SendMessage doesn't return until the message has been handled by the target window, and that won't happen until after a thread-switch that will allow the window's proc to process the message (see MSDN which points out that a window's proc can only run in the thread that created the window).

So, using SendMessage between threads will often result in horrible performance.

NigelQ
August 23rd, 2005, 10:34 PM
A little trick I use frequently when trying to do this type of thing is pass a structure (containing plain old data types - no classes) in the message to the thread and have the structure contain the handle of the requesting thread.


// Thread 1

struct MyStruct *pNewStruct = new struct MyStruct;

pNewStruct->m_dwRequestingThread = m_nThreadID; // store 'this' thread's ID in the request struct
pNewStruct->OtherStuff = whatever;

::PostThreadMessage(m_dwThread2_ID, MSG_SOME_MESSAGE, 0L, (LPARAM)pNewStruct);


Now in the other thread (handling the request)...


ON_THREAD_MESSAGE(MSG_SOME_MESSAGE, OnSomeMessage)

///

void CMyThread2::OnSomeMessage(WPARAM wParam, LPARAM lParam)
{
struct MyStruct *pRequestStruct = (struct MyStruct *)lParam;

if(pRequestStruct->m_dwRequestingThread != 0)
{
if(pRequestStruct->OtherStuff == what_im_looking_for)
{
::PostThreadMessage(pRequestStruct->m_dwRequestingThread, MSG_REPLY, 0L, 1234); // maybe a more informitive reply?
}
}

delete pRequestStruct; // <-- don't forget to delete the request structure here !

}


...and voila!

This might look a little clunky, but works just fine.

Remember - there's a reason why I said don't pass classes between the threads. If you do, you run the risk of confusing MFC - I'm sure there's a wealth of writing somewhere on not passing MFC objects between threads - I just don't have any useful references handy (and I'm too busy to go look :-).

You should be safe enough passing your own classes back and forth, but I rarely take that risk (because sooner or later your classes could end up containing MFC objects), relying instead on regular c-style structures and variables (POD types) which are sure to work every time.

Hope this helps,

- Nigel

DumbMonkey
August 24th, 2005, 05:40 AM
Thanks to you all for your help. From what i have found on the net and read here, there seems to be no problem with my code, apart from the use of PeekMessage which is now obsolete. I have replaced it with GetMessage, which also cuts down the processing of the thread and it does *seem* much better. Also put a sleep and retry function if PostThreadMessage fails.
All your help is much appreciated.

Andreas Masur
August 24th, 2005, 01:35 PM
Remember - there's a reason why I said don't pass classes between the threads. If you do, you run the risk of confusing MFC - I'm sure there's a wealth of writing somewhere on not passing MFC objects between threads - I just don't have any useful references handy (and I'm too busy to go look :-).
One have to be careful while passing 'CWnd' pointers between threads or applications since the MFC is not thread-safe at object level (only at class level).

As long as the functions do not access the window handle (m_hWnd) you are fine. But many functions need to go back to the specific window handle and then will cause a debug assertion (access vialotion in release mode). The reason is that the window handle maps are kept in thread local storage to ensure protection from simultaneous access from multiple threads. So...there is the possibility for example that one thread might have a mapping from a handle to a C++ object, but another thread might map the same handle to a different one.