A better thread class

Threads can be complicated beasts until you get used to them. They are certainly useful, but at the same time, they can add a lot of complexity. I have seen several attemps to provide the ultimate thread wrapper class for Win32, including MFC’s CWinThread and several others on C/C++ Users Journal, to name a few.

However, I’ve never been to keen on any of them. I always thought there had to be a better way. In December 1999, Allen Broadman and Eric Shaw published an article on CUJ called ”Executing a Class Member in its own thread” that provided a particular solution to the problem. It was very elegant in some respects and provided much welcome type safety and a lot of flexibility: It allowed you to create a thread and call any function on any object instance you wanted, provided the function had a certain signature.

They really had the right idea, but approached it the wrong way. While it was good and useful, it was unsuitable for any but the most basic use of threads. The particular problems they had were:

  • There was no way to keep the thread object around.
  • You were left with a raw thread handle, instead of wrapping that as well.

So I took their idea and implemented it in a way that fixed both of the problems above. It was rather simple: All you had to do was avoid having the function’s signature as a template parameter! This doesn’t reduce type safety at all because even in Broadman’s and Shaw’s implementation the function’s signature was known, and could simply be deduced from the object’s type.

Some time after writing this, I decided to rethink the approach I had, which encapsulated everything in a single class, and instead try something similar to what Broadman and Shaw had, which was to have a special stand-alone thread creation function that provided automatic type discovery. This meant splitting the Thread implementation in three different parts:

  • A Thread class, which wraps a thread HANDLE and ID, but does not provide means to create that thread. This si the object you get to keep when you create the thread, and provides wrappers around several useful apis, like ResumeThread(). It also has correctly defined copy constructor and assignment operators that use DuplicateHandle() internally.
  • A ThreadImpl<> template that creates the Thread object and has the internally-used ThreadProc.
  • A couple of Thread creation functions that provide the automatic type discovery.

Yet another advantage of my implementation is that the class template allows you to provide a thread creation class, so you can plug in your custom creation function. I supply two classes:

  • Win32Threader, which simply calls the CreateThread() Win32 api.
  • CrtThreader, which can be used with VC++ C Runtime library, which simply calls _beginthread().

To run threads, you can use one of the two RunOnThread() functions provided. The first template argument in each one is the type of the Creator class to use, and has to be provided explicitly at call time (see example below).

The difference between the two functions is that one is for starting threads on member functions, while the second overload is able to start threads on global standalone functions, or static member functions. This is done through the use of an adapter class, called GlobalAdaptor.

Using the template is pretty simple, here's an example:


class ThreadedObj {
public:
  DWORD some(int a) {
     printf ( "In thread: %d\n", a );
     return 0;
  }
};

DWORD StandAlone ( int b )
{
  printf ( "In thread: %d - %d\n", GetCurrentThreadId(), b );
  return 0;
}

using namespace Winterdom::Runtime::Threading;

ThreadedObj obj;
Thread thread = RunOnThread<Win32Threader>(obj, &ThreadedObj::some, 8);

// or something like this for a standalone function
//  Thread thread = RunOnThread<CrtThreader>(StandAlone, 8);

thread.WaitOn();

Grab the file here: winterdom_cpp.zip