Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

A C++ Thread Class

0.00/5 (No votes)
28 Jan 2004 2  
An article on wrapping the Win32 threading APIs.

Introduction

The C++ language invites for object oriented programming. The Win32 API is entirely based on the C programming language. Writing software for the Windows platform always requires the use of the Win32 API. Many developers who prefer C++ and object oriented programming would wish to have available appropriate C++ class libraries, to give their software a consistent object oriented look and feel.

The immense popularity of Java, and now .NET, is mostly based on the large number of classes that in fact make up the programming platform. Java and .NET application programmers just simply write their applications utilizing these classes whereas, by contrast, C++ programmers first write an infrastructure and then use it to write the applications. In this article, I will show you how to write a simple C++ class that wraps the Win32 thread related APIs.

Class Thread

The Java and .NET platform already have proposed some very good models and so we might as well make our model look similar. The advantage of it is that anyone familiar with Java or .NET can easily relate to it.

The threading models in Java as well as in .NET require that a thread object accepts a class method as its thread procedure. Here is an illustration:

Threading in Java

// define class with a threadable method

public class MyObject implements Runnable {
  // the thread procedure

  public void run() {
    // TODO: put the code here

  }
}

MyObject obj = new MyObject();
Thread thread = new Thread(obj);
tread.start();

Threading in .NET

// define class with a threadable method

public class MyObject {
  // the thread procedure

  public void Run() {
    // TODO: put the code here

  }
}

MyObject obj = new MyObject();
Thread thread = new Thread(new ThreadStart(obj.Run));
tread.Start();

The models are remarkably similar. Java requires the threadable object to implement the Runnable interface, and .NET, in a way, requires the same thing because the Thread classes on either platform expects a threadable procedure to be of this form: public void run().

The Java specification is rather simple. Just one simple interface exposing one simple method. The .NET specification is more sophisticated. The 'delegate' concept lends greater flexibility to the writing of multi-threaded programs. Here is an illustration:

// create a threadable object

public class MyObject {
  // first thread procedure

  public void ThreadProc1() {
    // TODO:    

  }
  // second thread procedure

  public void ThreadProc2() {
    // TODO:

  }
}

MyObject obj = new MyObject();

// create first thread

Thread thread1 = new Thread( new ThreadStart(obj.ThreadProc1) );
thread1.Start();

//create second thread

Thread thread2 = new Thread( new ThreadStart(obj.ThreadProc2) );
thread2.Start();

The .NET threading model offers more advantages. Any class method that is compatible with the ThreadStart delegate can be run as a thread procedure. And as the code snippet above illustrates, a single object instance can concurrently be accessed and manipulated by multiple threads. This is a very powerful feature.

We naturally prefer a C++ threading model to be as simple as that of Java and as flexible as that of .NET. Let us focus first on the Java-like simplicity. Here is a proposal:

// define the interface

struct IRunnable {
  virtual void run() = 0;
};

// define the thread class

class Thread {
public:
  Thread(IRunnable *ptr) {
    _threadObj = ptr;
  }
  void start() {
    // use the Win32 API here

    DWORD threadID;
    ::CreateThread(0, 0, threadProc, _threadObj, 0, &threadID);
  }
  
protected:
  // Win32 compatible thread parameter and procedure 

  IRunnable *_threadObj; 
  static unsigned long __stdcall threadProc(void* ptr) {
    ((IRunnable*)ptr)->run();
    return 0;
  }   
};

We can now write a multi-threaded program as elegantly as the Java folks can do.

// define class with a threadable method

class MyObject : IRunnable {
public:
  // the thread procedure

  virtual void run() {
    // TODO: put the code here

  }
}

MyObject *obj = new MyObject();
Thread thread = new Thread(obj);
tread->start();

It is so simple because we have buried the Win32 API call into a wrapper class. The neat trick here is the static method defined as part of our Thread class. We have thus emulated the simpler Java Thread class.

The .NET Thread and ThreadStart approach is a little harder to emulate. But we can still realize it in a way by using pointers to class methods. Here is the example:

// define class with a threadable method

class MyObject : IRunnable {
 // pointer to a class method

 typedef void (MyObject::* PROC)();
 PROC fp;
 
 // first thread procedure

 void threadProc1() {
   //TODO: code for this thread procedure

 }
 // second thread procedure

 void threadProc2() {
   //TODO: code for this thread procedure

 }
    
public:
  MyObject() {
    fp = threadProc1;
  }
  void setThreadProc(int n) {
    if(n == 1) 
        fp = threadProc1;
    else
    if(n == 2)
        fp = threadProc2;
  }
  // the thread procedure

  virtual void run() {
    (this->*fp)();
  }
};

MyObject *obj = new MyObject();

obj->setThreadProc(1);
Thread *thread1 = new Thread(obj);
thread1->start();

obj->setThreadProc(2);
Thread *thread2 = new Thread(obj);
thread2->start();

The actual threadable method run() now uses a pointer to a class method to run the appropriate thread procedure. That pointer must be correctly initialized before a new thread is started.

Conclusion

Wrapping the Win32 APIs into C++ classes is the preferred practice. The Java and .NET platforms provide us with well defined models. And by comparison, these models are so similar that defining C++ classes for a thread class, socket class, stream class, etc. should just be a matter of following the provided documentation.

You may download the Thread class and try it out. I have designed it to be as simple as possible but you may enhance it by wrapping an additional number of thread related APIs, e.g. SetThreadPriority, GetThreadPriority etc.

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