Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C++

Effective Threads in C++ - Part 2: The ExitableThread Class

2.18/5 (5 votes)
22 Nov 20062 min read 1   616  
Wrapping the Win32 Thread API into a C++-friendly class.

Introduction

Over the past few years, multithreaded apps have become the mainstay of my development repertoire. I've even found myself writing multithreaded apps where it wasn't needed. Worker threads allow Win32 applications to improve the user experience and increase performance.

With this varied experience, I've come up with a set of patterns that I find myself using frequently (OK, so they're not patterns in the classical sense; more of paradigms). I've written classes which streamline the use of these paradigms in all situations.

In part 2 of this three article series, I will show the most frequently used of these paradigms: the Exitable Thread paradigm. The majority of worker threads perform the same action over and over again within some kind of loop. Whether it is processing a number of different files, exporting data from one format to another, or reading message coming across the wire, these actions have a very specific rhythm.

Description of the Exitable Thread pattern

The basis of the Exitable Thread pattern is the pairing of a thread with a Win32 Event object. This Event object is unsignaled until an external event (the user pressing a cancel button, app shutdown, etc). signals the event. At the beginning or end of each iteration of the worker thread, the thread checks the exit event. If the event is set, it exits the loop, performing any needed cleanup.

The ExitableThread class

The ExitableThread class inherits from the Thread class created in article #1 of this series. This allows us to capitalize on the code for the basic thread creation and method invocation, while adding the Exit Event object and associated methods.

template<class T, class P>
class ExitableThread : public Thread<T, P>
{
public:
    typedef void (T::*ThreadFunc)( P );

    ExitableThread();
    virtual ~ExitableThread();

    // ExitThread methods - Called within the context of an
    // external thread to instruct the embedded (running)
    // thread to exit.  
    //
    // ExitThread() - Signals the event and immediately 
    // returns.  
    //
    // ExitThreadAndWait() - Signals the event and waits 
    // until the thread actually exits or the timeout
    // expires.  Returns true if the thread exited, or
    // false if the timeout expired
    void ExitThread();
    bool ExitThreadAndWait( DWORD timeoutMS = 5000 );

    // IsExitEventSet - Called by the embedded (running)
    // thread to test if the exit event is set.  Returns
    // true if the event has been set, and the thread
    // should exit, and false otherwise
    bool IsExitEventSet();
};

The comments speak for the code. The new ExitThread() methods allow other threads to wait on the encapsulated thread to exit. These methods set the thread's exit event. The ExitThread() method sets the event and immediately returns to the caller, while the ExitThreadAndWait() waits for the thread handle to become signaled. If it does not exit before the specified timeout elapses, the thread is terminated.

Using the ExitableThread class

The ExitableThread class is used by classes in the same way that the Thread parent class is. However, the worker thread's method should be an iterative process, which periodically calls the IsExitEventSet() method to see if it should exit.

void TestClass::DoExitableWork( int i )
{
    Files::iterator it;
    for (it = files.begin(); it != files.end(); it++)
    {
        ProcessFile( *it );

        // Check the Exit Event
        if (m_thread.IsExitEventSet())
            break;
    }
}

Conclusion

The Exitable Thread is a pattern (or paradigm) which helps control worker threads and their lifetime. When an external circumstance warrants a thread to exit, the Exitable Thread pattern allows the worker thread to get the message and cleanup properly and release any resources. The ExitableThread class allows this pattern to easily be inserted wherever an iterative worker thread is needed.

In the final part of this short series, we will look at how to extend both the Thread and ExitableThread classes into a powerful set of classes, which removes any assumptions made about the caller and callee.

History

  • 2006.11.22 - First revision.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here