. Home Feedback Contents Search

Multi-Threading 

Back Up Next

Critical section

MFC encapsulates the critical section within a CCriticalSection class.

Critical section is the easiest of the thread control devices. It is only useful from within a single process. It essentially stops all other threads from enter a critical section until the first thread has released it. If multiple threads are trying to access a locked critical section, there is no guarantee which thread will get it when it becomes free.

Generally, I declare a CCriticalSection somewhere in my code, generally as a class member but sometimes as a standalone global. Thereafter, it protects access to resources with a Lock() and releases the CCriticalSection for other threads with an Unlock.

#include <afxmt.h>

class CSomething
    {
    .
    public:
    .
    .  bool bOne();

    protected:

    CCriticalSection m_cs;
    .
    .
    };

bool CSomething::bOne()
    {
    BOOL      bLocked = m_cs.Lock( 100 );
    .
    .
    if (bLocked)
        m_cs.Unlock();

    return bLocked;
    }

 

Mutex

Semaphore

Event

Terminating one thread from another

Lets assume that we have a worker thread running in a loop and that it has done something really bad and we’ve flown in a guy from a Texas death row to terminate it. Just to make things easy for this guy because he is, after all, expensive and you know what they say, time is money, we’ve set the worker thread up to be cooperative. All we have to do is signal it by setting a flag and it will cease looping and self terminate.

If we don’t care about waiting until the thread has terminated then we don’t have anything else to talk about. On the other hand, sometimes you need to verify the end of the thread. There are two basic ways of this, the worker thread does something special to notify the world like set a flag or an event or the outside agent monitors the state of the thread’s handle. When the handle stops being valid, the thread has ceased. The big advantage of this is that this happens when the thread is completely gone. The disadvantage is the caller has to have some way of gaining access to the thread’s handle. As for the flag method, the thread can set it as it exits but that leaves you in a race condition as well as having to forge some mechanism that makes a flag available to both a caller and the worker thread. Events are less closely bonded but the thread is not yet closed out at the time that it is telling the world that it is.

There’s one other little thing to worry about while waiting for the worker to finish up. If the outside agent is hung in a loop awaiting the thread's demise, then it isn’t doing much that is useful. If said outside agent is operating on the message pump’s dime then no other messages are going to be handled unless we do something special. On the other hand, if we don’t care about message pump then that makes life easier. In any case, it is entirely possible that the thread termination may have something untoward going on such that the thread termination notification never gets a chance to happen. We do not want our terminator to get hung up so he should have a good escape clause written into his contract.

Let’s assume that the thread is executing within the confines of a class and that this thread is monitoring the state of m_bTerminate to flag when it is to quit. The class takes care of both the flag and the thread handle. Further, let’s assume that we can get here as the result of a message so we want to provide for the processing of other messages. If we don’t care about

unsigned long WINAPI ThreadProc(void *pThreadProc)
    {
    CThreadProc* pTP = (CThreadProc *)pThreadProc;
    if (pTP)
        {
        pTP->m_bTerminate = false;
        return pTP->uiThreadProc()
        }
    else
        return 0;
    }


UINT CThreadProc::uiThreadProc()
    {
    while (!m_bTerminate)
        Sleep( 50 );

    return 0;
    }


void CThreadProc::Terminate()
    {
    // Tell the thread that it is time to quit.

    m_bTerminate = true;

    // Calculate a time out of 2 seconds from now.

    DWORD    dwTimeOut = GetTickCount() + 2000;

    // Wait for the thread handle to go invalid or the timeout to happen.

    while ( !(AtlWaitWithMessageLoop( m_hThread )) && (dwTimeOut<GetTickCount()) )
        {
        // Yield a bit of the time slice while we wait for
        // the thread to terminate.

        Sleep(50);
        }
    }

Back Up Next