Click here to Skip to main content
15,909,747 members
Home / Discussions / C / C++ / MFC
   

C / C++ / MFC

 
GeneralRe: Main MFC and its Threads Pin
jmkhael13-May-04 23:23
jmkhael13-May-04 23:23 
GeneralRe: Main MFC and its Threads Pin
sweep12314-May-04 0:26
sweep12314-May-04 0:26 
GeneralRe: Main MFC and its Threads Pin
Jitendra gangwar14-May-04 0:47
Jitendra gangwar14-May-04 0:47 
GeneralRe: Main MFC and its Threads Pin
Roger Stoltz14-May-04 1:30
Roger Stoltz14-May-04 1:30 
GeneralRe: Main MFC and its Threads Pin
sweep12314-May-04 2:02
sweep12314-May-04 2:02 
GeneralRe: Main MFC and its Threads Pin
Roger Stoltz14-May-04 3:38
Roger Stoltz14-May-04 3:38 
GeneralRe: Main MFC and its Threads Pin
Grahamfff14-May-04 11:39
Grahamfff14-May-04 11:39 
GeneralRe: Main MFC and its Threads Pin
Roger Stoltz16-May-04 13:13
Roger Stoltz16-May-04 13:13 
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", dwWaitResult );
            ::OutputDebugString( msg );
            bQuit = TRUE;
        }
        break;
    }
}
delete m_pMyThread;
m_pMyThread = NULL;

2. The thread might need some initialization such as getting a marshaled interface and if it fails I usually want to disable controls or similar before continuing. I do this by waiting for events that are signalled from the newly spawned thread informing the function that spawned the thread whether it has started successfully or not. Regarding these events my header file usually looks something like this:
enum
{
    SuccessIndex,
    ErrorIndex,
    WinMsgIndex //Index returned by MsgWaitFor... in case of a message, this is also the number of events in the array
};
HANDLE m_hThreadStartEvents[WinMsgIndex];

My constructor would contain something like this...
m_hThreadStartEvents[SuccessIndex] = ::CreateEvent( NULL, TRUE, FALSE, NULL );
m_hThreadStartEvents[ErrorIndex] = ::CreateEvent( NULL, TRUE, FALSE, NULL );
and my destructor contains cleanup code...
::CloseHandle( m_hThreadStartEvents[SuccessIndex] );
::CloseHandle( m_hThreadStartEvents[ErrorIndex] );

This will allow me to pass the event array for the "objects" to wait for when calling MsgWaitForMultipleObjects(). Hence the code after the row containing m_pMyThread->ResumeThread(), showing how I start new threads above, will look something like...
dwWaitResult = ::MsgWaitForMultipleObjects( WinMsgIndex, m_hThreadStartEvents, FALSE, INFINITE, QS_ALLINPUT );
followed by code similar to the one showing how I wait for the thread to finish and still processing messages with one little nice twist: in the switch statement you are able to use the values of the enum to test the return value from MsgWait... like this:
case SuccessIndex:
    // Do whatever needs to be done if the thread started successfully
    break;
    
case ErrorIndex:
    // Do whatever needs to be done if the thread failed somehow
    break;
    
case WinMsgIndex:
    // We now have messages in the threads message queue to process
    // How this is done is shown above
    break;

Quite often a worker thread's controlling function is built up with a loop similar to
while( !m_bStopThread )
{
    ....
    ....
}
and sometimes the thread has the ability to terminate itself by simply returning from the controlling function. Your GUI thread has no way of knowing this unless it is polling the thread status. To inform your GUI thread if the spawned thread is about to finish and have a chance to free allocated resources, you simply post a message before returning from the threads controlling function. In the message handler you can wait for the thread to finish and free up allocated resources such as the CWinThread object (how is shown above).

I hope you find something useful in it.
--
Roger
with probably too much time to spare Unsure | :~
GeneralRe: Main MFC and its Threads Pin
sweep12317-May-04 2:00
sweep12317-May-04 2:00 
QuestionHow to use Amazon Web Services.. Pin
Sumit Kapoor13-May-04 21:56
Sumit Kapoor13-May-04 21:56 
AnswerRe: How to use Amazon Web Services.. Pin
Anthony_Yio14-May-04 1:46
Anthony_Yio14-May-04 1:46 
GeneralCListCtrl and CImageList question Pin
DaFrawg13-May-04 21:52
DaFrawg13-May-04 21:52 
GeneralRe: CListCtrl and CImageList question Pin
DaFrawg23-May-04 22:43
DaFrawg23-May-04 22:43 
Questionwhich Project type to use? Pin
frumm13-May-04 21:48
frumm13-May-04 21:48 
AnswerRe: which Project type to use? Pin
Maxwell Chen13-May-04 21:54
Maxwell Chen13-May-04 21:54 
AnswerRe: which Project type to use? Pin
Cedric Moonen13-May-04 23:01
Cedric Moonen13-May-04 23:01 
AnswerRe: which Project type to use? Pin
hasansheik14-May-04 0:18
hasansheik14-May-04 0:18 
GeneralRe: which Project type to use? Pin
frumm14-May-04 6:29
frumm14-May-04 6:29 
GeneralDVD Class Pin
foxele13-May-04 21:23
foxele13-May-04 21:23 
GeneralRe: DVD Class Pin
David Crow14-May-04 4:29
David Crow14-May-04 4:29 
Generaltooltips in CTreeCtrl to show some other info rather than the node name Pin
SVPG13-May-04 21:22
SVPG13-May-04 21:22 
GeneralUSB Communication. Pin
Abdul Munaf Chhatra13-May-04 19:56
Abdul Munaf Chhatra13-May-04 19:56 
Generalautorun Pin
kanetheterrible113-May-04 19:47
kanetheterrible113-May-04 19:47 
GeneralRe: autorun Pin
DaFrawg14-May-04 1:39
DaFrawg14-May-04 1:39 
GeneralSkinMagic library Pin
Krugger40413-May-04 19:31
Krugger40413-May-04 19:31 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.