Main MFC and its Threads
-
I have an MFC application which creates a thread to receive a stream of data from another application in bursts. Now the thread is started by the main MFC program via:- m_DisplayTextThread = ::AfxBeginThread(CTestGUI1Dlg::DisplayTextThread, (LPVOID) &m_DisplayThreadData); and passed the pointer (this) of the main MFC application in the structure m_DisplayThreadData in order for it to access the methods/properties of the main MFC application that require updating. This causes an Assertion fault, and it was suggested (in a previous post) that PostThreadMessage be used to communicate from the thread to the main application. My question is - what is the scheme to use for this type of activity, where the GUI needs to reflect data received, but when the receive processing is done in a different thread. How would this be done? I have looked up PostThreadMessage but dont see how to use it. I have tended to pass into the thread the neccessary data/pointer the thread required, but this time I have problems. If I use a smple timer in place of the thread all is well, but have to run slow to ensure that I do not loose data.
-
I have an MFC application which creates a thread to receive a stream of data from another application in bursts. Now the thread is started by the main MFC program via:- m_DisplayTextThread = ::AfxBeginThread(CTestGUI1Dlg::DisplayTextThread, (LPVOID) &m_DisplayThreadData); and passed the pointer (this) of the main MFC application in the structure m_DisplayThreadData in order for it to access the methods/properties of the main MFC application that require updating. This causes an Assertion fault, and it was suggested (in a previous post) that PostThreadMessage be used to communicate from the thread to the main application. My question is - what is the scheme to use for this type of activity, where the GUI needs to reflect data received, but when the receive processing is done in a different thread. How would this be done? I have looked up PostThreadMessage but dont see how to use it. I have tended to pass into the thread the neccessary data/pointer the thread required, but this time I have problems. If I use a smple timer in place of the thread all is well, but have to run slow to ensure that I do not loose data.
I would suggest using PostThreadMessage just to signal to the main thread (MFC application) that something happened in the receive thread. The receive thread updates the (pointer of the) data passed and just signal to the main thread to do his work. I personnaly would go for events. Papa while (TRUE) Papa.WillLove ( Bebe ) ;
-
I would suggest using PostThreadMessage just to signal to the main thread (MFC application) that something happened in the receive thread. The receive thread updates the (pointer of the) data passed and just signal to the main thread to do his work. I personnaly would go for events. Papa while (TRUE) Papa.WillLove ( Bebe ) ;
OK, but how do you use PostThreadMessage in the thread to arrange a routine to run in the main application. Also, you said use Events, but that means another thread waiting on the event and needs to arrange the main MFC application to do something. I dont understand how to get something running in the main MFC application from a thread other than the use of the 'this' pointer passed into the thread. But thats causing a problem.
-
OK, but how do you use PostThreadMessage in the thread to arrange a routine to run in the main application. Also, you said use Events, but that means another thread waiting on the event and needs to arrange the main MFC application to do something. I dont understand how to get something running in the main MFC application from a thread other than the use of the 'this' pointer passed into the thread. But thats causing a problem.
try PostMessage in place of PostThreadMessage. As I understand, Here you want to notify the main application when the data is received by the thread. so it would be the right option to use PostMessage for posting the messages to the main application window. You can you the pointer to the Main application windows/ Dialog whatever the UserInterce Object to which you want to be updated. You can implement it easily - the steps is as follows 1. define a user defined Message. 2. provide the handler associated with that message in the UserInterface object (Application Window/ Dialog) 3. use PostMessage as you receive the data in Thread. enjoy ;) Jitendra
-
I have an MFC application which creates a thread to receive a stream of data from another application in bursts. Now the thread is started by the main MFC program via:- m_DisplayTextThread = ::AfxBeginThread(CTestGUI1Dlg::DisplayTextThread, (LPVOID) &m_DisplayThreadData); and passed the pointer (this) of the main MFC application in the structure m_DisplayThreadData in order for it to access the methods/properties of the main MFC application that require updating. This causes an Assertion fault, and it was suggested (in a previous post) that PostThreadMessage be used to communicate from the thread to the main application. My question is - what is the scheme to use for this type of activity, where the GUI needs to reflect data received, but when the receive processing is done in a different thread. How would this be done? I have looked up PostThreadMessage but dont see how to use it. I have tended to pass into the thread the neccessary data/pointer the thread required, but this time I have problems. If I use a smple timer in place of the thread all is well, but have to run slow to ensure that I do not loose data.
sweep123 wrote: Now the thread is started by the main MFC program via:- m_DisplayTextThread = ::AfxBeginThread(CTestGUI1Dlg::DisplayTextThread, (LPVOID) &m_DisplayThreadData); and passed the pointer (this) of the main MFC application in the structure m_DisplayThreadData in order for it to access the methods/properties of the main MFC application that require updating. Regarding thread startup... Without exceptions I pass the this-pointer when spawning threads since I consider it good modeling and encapsulation. It also simplifies my life since I can use PostMessage from my thread in the way that you want/need. My header files looks something like this:
class CMyDialog : public CDialog //or another suitable CWnd derived base class
{
.....
protected:
static UINT MyThreadFn( LPVOID pThis ) { return ((CMyDialog*)pThis)->MyThreadFn(); }
UINT MyThreadFn(); // The thread controlling function
volatile BOOL m_bStopMyThread;
CWinThread* m_pMyThread;
....
};This way I get access to member variables from the thread function MyThread() without polluting the code with a lot of type casting. sweep123 wrote: My question is - what is the scheme to use for this type of activity, where the GUI needs to reflect data received, but when the receive processing is done in a different thread. How would this be done? I have looked up PostThreadMessage but dont see how to use it. If you use the thread solution above you can forget about PostThreadMessage and use PostMessage instead from your thread since the thread function is a member of a CWnd derived class. All you need is to define a message ID for your message, declare a message handler, add a message entry in the message map and implement your message handler. In code it would look something like this for the header file:
#define UWM_MY_MESSAGE (WM_APP + 1)
class CMyClass : public CDialog
{
....
afx_msg LRESULT OnMyMessage( WPARAM wParam, LPARAM lParam );
....
};...and for the cpp file:
....
BEGIN_MESSAGE_MAP(CMyClass, CDialog)
....
ON_MESSAGE( UWM_MY_MESSAGE, OnMyMessage )
....
END_MESSAGE_MAP()
....
....
LRESULT CMyClass::OnMyMessage( WPARAM wParam, LPARAM lParam )
{
// Do whatever you need to do here
return 0;
}If you want you can send the length and a pointer to data from your thread using the two parameters wParam and lParam. The memory allocation is done in your thread and deallocation is
-
sweep123 wrote: Now the thread is started by the main MFC program via:- m_DisplayTextThread = ::AfxBeginThread(CTestGUI1Dlg::DisplayTextThread, (LPVOID) &m_DisplayThreadData); and passed the pointer (this) of the main MFC application in the structure m_DisplayThreadData in order for it to access the methods/properties of the main MFC application that require updating. Regarding thread startup... Without exceptions I pass the this-pointer when spawning threads since I consider it good modeling and encapsulation. It also simplifies my life since I can use PostMessage from my thread in the way that you want/need. My header files looks something like this:
class CMyDialog : public CDialog //or another suitable CWnd derived base class
{
.....
protected:
static UINT MyThreadFn( LPVOID pThis ) { return ((CMyDialog*)pThis)->MyThreadFn(); }
UINT MyThreadFn(); // The thread controlling function
volatile BOOL m_bStopMyThread;
CWinThread* m_pMyThread;
....
};This way I get access to member variables from the thread function MyThread() without polluting the code with a lot of type casting. sweep123 wrote: My question is - what is the scheme to use for this type of activity, where the GUI needs to reflect data received, but when the receive processing is done in a different thread. How would this be done? I have looked up PostThreadMessage but dont see how to use it. If you use the thread solution above you can forget about PostThreadMessage and use PostMessage instead from your thread since the thread function is a member of a CWnd derived class. All you need is to define a message ID for your message, declare a message handler, add a message entry in the message map and implement your message handler. In code it would look something like this for the header file:
#define UWM_MY_MESSAGE (WM_APP + 1)
class CMyClass : public CDialog
{
....
afx_msg LRESULT OnMyMessage( WPARAM wParam, LPARAM lParam );
....
};...and for the cpp file:
....
BEGIN_MESSAGE_MAP(CMyClass, CDialog)
....
ON_MESSAGE( UWM_MY_MESSAGE, OnMyMessage )
....
END_MESSAGE_MAP()
....
....
LRESULT CMyClass::OnMyMessage( WPARAM wParam, LPARAM lParam )
{
// Do whatever you need to do here
return 0;
}If you want you can send the length and a pointer to data from your thread using the two parameters wParam and lParam. The memory allocation is done in your thread and deallocation is
-
Many thanks Roger, I shall try this out ASAP. I assume that I can define UWM_MY_MESSAGE as follows:- #define UWM_MY_MESSAGE 0x100, or should I place it into the resource.h
sweep123 wrote: I assume that I can define UWM_MY_MESSAGE as follows:- #define UWM_MY_MESSAGE 0x100, or should I place it into the resource.h When declaring your own message ID's you should at least use the WM_APP as an offset like the code example I posted earlier. WM_APP is defined in winuser.h as 0x8000. If you should use another offset you may create a conflict with an already existing message ID. In your case from above if you should use the value 0x100 that would be in conflict with the system message WM_KEYDOWN. Message ID's are in no way connected with resources which ID's are defined in resource.h. You simply define the message ID for your message as
#define UWM_GOT_DATA (WM_APP + 1)
System messages have define's like WM_PAINT, WM_CLOSE and WM_QUIT. Placing the capital letter 'U' in front of the message ID is like a coding convention some of us like to use. User defined messages will easily be recognized as they begin with the capital letter 'U'. No one can force you to follow a coding convention (unless it's your boss), but it makes the code easier to read IMO. I recommend that you have a look at Joseph Newcomer's mvp tips page at http://www.flounder.com/mvp_tips.htm and read his essay about message management. You will find a lot of really valuable tips from his pages. BTW, regarding threads in general... You have to protect your data that is shared between the threads, otherwise you will end up with data corruption and other undesired behaviour. At least use critical sections. You can read about this too at Newcomer's pages. -- Roger
-
sweep123 wrote: I assume that I can define UWM_MY_MESSAGE as follows:- #define UWM_MY_MESSAGE 0x100, or should I place it into the resource.h When declaring your own message ID's you should at least use the WM_APP as an offset like the code example I posted earlier. WM_APP is defined in winuser.h as 0x8000. If you should use another offset you may create a conflict with an already existing message ID. In your case from above if you should use the value 0x100 that would be in conflict with the system message WM_KEYDOWN. Message ID's are in no way connected with resources which ID's are defined in resource.h. You simply define the message ID for your message as
#define UWM_GOT_DATA (WM_APP + 1)
System messages have define's like WM_PAINT, WM_CLOSE and WM_QUIT. Placing the capital letter 'U' in front of the message ID is like a coding convention some of us like to use. User defined messages will easily be recognized as they begin with the capital letter 'U'. No one can force you to follow a coding convention (unless it's your boss), but it makes the code easier to read IMO. I recommend that you have a look at Joseph Newcomer's mvp tips page at http://www.flounder.com/mvp_tips.htm and read his essay about message management. You will find a lot of really valuable tips from his pages. BTW, regarding threads in general... You have to protect your data that is shared between the threads, otherwise you will end up with data corruption and other undesired behaviour. At least use critical sections. You can read about this too at Newcomer's pages. -- Roger
One futher question, how do you start your thread, i.e. in CTestGUI1Dlg::OnInitDialog() m_DisplayTextThread = ::AfxBeginThread(CTestGUI1Dlg::DisplayThreadData, (LPVOID)this); or do you still pass over a structure and typecast to this pointer? m_DisplayTextThread = ::AfxBeginThread(CTestGUI1Dlg::DisplayTextThread, (LPVOID)&m_DisplayThreadData); and in the thread:- DisplayThreadData* ThreadData = (DisplayThreadData*)param; CTestGUI1Dlg* pxDlg = (CTestGUI1Dlg*) ThreadData->_this; grahamfff
-
One futher question, how do you start your thread, i.e. in CTestGUI1Dlg::OnInitDialog() m_DisplayTextThread = ::AfxBeginThread(CTestGUI1Dlg::DisplayThreadData, (LPVOID)this); or do you still pass over a structure and typecast to this pointer? m_DisplayTextThread = ::AfxBeginThread(CTestGUI1Dlg::DisplayTextThread, (LPVOID)&m_DisplayThreadData); and in the thread:- DisplayThreadData* ThreadData = (DisplayThreadData*)param; CTestGUI1Dlg* pxDlg = (CTestGUI1Dlg*) ThreadData->_this; grahamfff
Sorry about the delay, but here it goes... Have a look at the example I sent earlier. The inline function CMyClass::MyThreadFn( LPVOID pThis ) will not work unless I start the thread passing the this pointer according to
m_pMyThread = AfxBeginThread( MyThreadFn, this )
One of the things I want to avoid is type casting inside my thread controlling function. IMO the code will be more readable without it. A few more tips if you like... Usually when I spawn new threads there are two situations I want to handle before I unleash the new thread: 1. I want to be able to wait for the thread when it finishes and that requires that the CWinThread object has its m_bAutoDelete member set to FALSE. Otherwise the CWinThread object will free all resources including the thread handle which is used for waiting. I set the m_bAutoDelete member when I spawn the thread and that's why I create it suspended. In code it will look something like this:
m_pMyThread = AfxBeginThread( MyThreadFn, this, 0, 0, CREATE_SUSPENDED, NULL );
if( m_pMyThread )
{
m_pMyThread->m_bAutoDelete = FALSE;
m_pMyThread->ResumeThread();
}When I later stop the thread I wait for it to finish with some of the wait functions, preferrably MsgWaitForMultipleObjects since it allows me to pump messages preventing the GUI from being locked. Or when COM is involved, this thread usually needs to process COM related messages to avoid a deadlock situation. The waiting is accomplished by passing the thread handle as the "object" to wait for. The CWinThread object must also be freed with a call to delete. Something like this in code:
DWORD dwWaitResult;
BOOL bQuit = FALSE;
while( !bQuit )
{
dwWaitResult = ::MsgWaitForMultipleObjects( 1, &m_pMyThread->m_hThread, FALSE, INFINITE, QS_ALLINPUT );
switch( dwWaitResult )
{
case WAIT_OBJECT_0:
bQuit = TRUE;
break;case WAIT\_OBJECT\_0 + 1: { MSG msg; while( ::PeekMessage( &msg, NULL, 0, 0, PM\_REMOVE ) ) { ::DispatchMessage( &msg ); } } break; case WAIT\_FAILED: { CString msg; msg.Format( "Wait failed. Error code 0x%x.\\n", GetLastError() ); ::OutputDebugString( msg ); bQuit = TRUE; } break; default: { CString msg; msg.Format( "Unexpected wait result: 0x%x.\\n", dwWaitResul
-
Sorry about the delay, but here it goes... Have a look at the example I sent earlier. The inline function CMyClass::MyThreadFn( LPVOID pThis ) will not work unless I start the thread passing the this pointer according to
m_pMyThread = AfxBeginThread( MyThreadFn, this )
One of the things I want to avoid is type casting inside my thread controlling function. IMO the code will be more readable without it. A few more tips if you like... Usually when I spawn new threads there are two situations I want to handle before I unleash the new thread: 1. I want to be able to wait for the thread when it finishes and that requires that the CWinThread object has its m_bAutoDelete member set to FALSE. Otherwise the CWinThread object will free all resources including the thread handle which is used for waiting. I set the m_bAutoDelete member when I spawn the thread and that's why I create it suspended. In code it will look something like this:
m_pMyThread = AfxBeginThread( MyThreadFn, this, 0, 0, CREATE_SUSPENDED, NULL );
if( m_pMyThread )
{
m_pMyThread->m_bAutoDelete = FALSE;
m_pMyThread->ResumeThread();
}When I later stop the thread I wait for it to finish with some of the wait functions, preferrably MsgWaitForMultipleObjects since it allows me to pump messages preventing the GUI from being locked. Or when COM is involved, this thread usually needs to process COM related messages to avoid a deadlock situation. The waiting is accomplished by passing the thread handle as the "object" to wait for. The CWinThread object must also be freed with a call to delete. Something like this in code:
DWORD dwWaitResult;
BOOL bQuit = FALSE;
while( !bQuit )
{
dwWaitResult = ::MsgWaitForMultipleObjects( 1, &m_pMyThread->m_hThread, FALSE, INFINITE, QS_ALLINPUT );
switch( dwWaitResult )
{
case WAIT_OBJECT_0:
bQuit = TRUE;
break;case WAIT\_OBJECT\_0 + 1: { MSG msg; while( ::PeekMessage( &msg, NULL, 0, 0, PM\_REMOVE ) ) { ::DispatchMessage( &msg ); } } break; case WAIT\_FAILED: { CString msg; msg.Format( "Wait failed. Error code 0x%x.\\n", GetLastError() ); ::OutputDebugString( msg ); bQuit = TRUE; } break; default: { CString msg; msg.Format( "Unexpected wait result: 0x%x.\\n", dwWaitResul