Home Search Contact us About us
Title Using threads
Summary This note shows how to create and use threads for simple processing. It also touches on synchronisation.
Contributor John McTainsh
Published 1-Nov-2000
Last updated 1-Nov-2000
Page rating   75% for 18 votes Useless Brilliant

Description.

Threads are an important and tricky part of a multi tasking operating system. This article will show how to use threads and mutex but will not detail thread design issues such as Deadlocks and Spinlocks.

How to start a thread.

It is necessary to create a function to run when the thread starts. This will continuously run until the function returns. The programmer should either use a flag or counter to limit the number of times the process loops.

//Function to display the thread count 20 times and terminate
UINT StartPlayingThread(LPVOID param)
{
    AFX_MANAGE_STATE( AfxGetAppModuleState( ) );    //Thread safe MFC access.
    TRACE( _T("StartPlayingThread(%p)\n"), param );
    int *pnThreadNo = (int*)param;
    ASSERT( pnThreadNo );

    //Loop recording the count
    for( int nCnt = 0; nCnt < 20; nCnt++ )
    {
        TRACE( _T("Count %d on thread %d\n"), nCnt, *pnThreadNo );
        Sleep( 1 );
    }

    //Clean up
    delete pnThreadNo;
    return 0;
}

To launch the thread call AfxBeginThread with the starting function name and one pointer. In this example the pointer is to an integer. This pointer is a good way to share data with the thread. DO NOT pass a pointer to a local variable as this may go out of scope and be deleted before the thread that is using this memory terminates.

    //Run thread one
    int *pNo = new int;
    if( pNo )
    {
        *pNo = 1;
        AfxBeginThread( &StartPlayingThread, pNo );
    }

    //Run thread two
    int *pNo2 = new int;
    if( pNo2 )
    {
        *pNo2 = 2;
        AfxBeginThread( &StartPlayingThread, pNo2 );
    }

In the above example the two threads will run in parallel. Run in debug and view the trace log to see the output.

Using Mutex.

As not all objects are "thread safe" (able to be processed by two threads at the same time) it is often necessary to stop processing in a certain area until another thread is finished in that area. In the example that follows g_nCounter is incremented after an exact match test is performed. If both threads increment g_nCounter at the same time 33 could be missed. EnterCriticalSection is used to hold other threads out of the testing/processing area until the thread is finished in this area.

//Shared Global counter
static int g_nCounter = 0;

//Function to loop until global g_nCounter == 33
UINT StartPlayingThread(LPVOID param)
{
    AFX_MANAGE_STATE( AfxGetAppModuleState( ) );    //Thread safe MFC access.
    TRACE( _T("StartPlayingThread(%p)\n"), param );
    LPCRITICAL_SECTION lpCritSection = (LPCRITICAL_SECTION)param;
    ASSERT( lpCritSection );

    //Loop recording the count
    bool bRun = true;
    while( bRun )
    {
        EnterCriticalSection( lpCritSection );      //Only one thread in here
        if( g_nCounter == 33 )
            bRun = false;
        else
            g_nCounter++;
        TRACE( _T("Thread ID=%ld, Count=%d\n"), AfxGetThread()->m_nThreadID, g_nCounter );
        LeaveCriticalSection( lpCritSection );
        Sleep( 1 );
    }
   return 0;
}

The following code creates a Critical Section handler to be shared by two threads that increment a shared integer resource. Once the threads are started they are monitored until they exit or a 5 second timer elapses.

   //Setup the mutex handler
    CRITICAL_SECTION CriticalSection;
    InitializeCriticalSection( &CriticalSection );

    //Run thread one
    CWinThread* wt1 = AfxBeginThread( &StartPlayingThread, &CriticalSection );
    CWinThread* wt2 = AfxBeginThread( &StartPlayingThread, &CriticalSection );

    //Wait for the threads to terminate in 5-10 seconds
    if( WaitForSingleObject( wt1->m_hThread, 5000 ) == WAIT_TIMEOUT )
    {
        TRACE( _T("ERROR : Thread wt1. Shut Down Failed!!\n") );
        exit( 0 );
    }
    if( WaitForSingleObject( wt2->m_hThread, 5000 ) == WAIT_TIMEOUT )
    {
        TRACE( _T("ERROR : Thread wt2. Shut Down Failed!!\n") );
        exit( 0 );
    }

    //Clean up
    TRACE( _T("Threads exited OK!\n") );
    DeleteCriticalSection( &CriticalSection );

NOTE: It is important to note that it is not possible (to my knowledge) to terminate a thread other than gracefully exiting thread function using software methods or terminating the application. In the previous example if 5 seconds has passed and the thread has not terminated it will NOT be forced to shut down. For this reason it is important to plan how a the thread is going to communicate and be terminated when designing the application. It is also necessary to test the program on multi-processor systems which may process threads differently that single processor machines.

Comments Date
Home Search Contact us About us