Download
Grab the thread.cpp and thread.h source files.
Introduction
Today I decided to write a cross platform thread class. After a quick look around, the contenders for the job of hiding operating system dependent code seemed to be:
As I’m after simplicity, SDL seems the appropriate choice as the API is basic and quite low level, yet I’m not exposed to any platform specific code. One thing it’s missing that I thought might become useful in the future is thread priorities, but for now that’s something I can live without.
The Class
The three SDL functions I need to use for this class are:
| Function | Description |
|---|---|
| SDL_CreateThread | Create the initial thread |
| SDL_WaitThread | Wait for the thread to finish executing |
| SDL_KillThread | Force the thread to die |
The first thing we need to do is to be able to start the thread. We do this with the following code:
void
Thread::start()
{
if (!m_running)
{
m_running = true;
m_thread = SDL_CreateThread(runThread, this);
}
}
First we do a simple check to see if the thread has already been created, then we create the thread passing the entry function to the thread as the first function, and a pointer to this class as the second. The reason behind this combination of parameters, is because the first parameter must be a simple function pointer, and cannot point to a member function of a class. runThread() is a static function of on the class which fulfills this requirement. We therefore pass the the object pointer in as well so we can reference back to ourselves.
This becomes more obvious in the entry point function:
int
Thread::runThread(void *data)
{
Illuminate::Thread *thread = static_cast
(data);
thread->run();
return true;
}
In this function, we first cast the data parameter back to the original Thread object which originally created the thread. We can then call the run() method which is the virtual method implemented in the subclass. We also keep track of the running state of the thread which can be accessed from the isRunning() method, and reset m_thread back to 0 so the thread can be started again.
Usage
Derive from the Thread abstract base class. Implement the void run() method. Construct your new class as an object and call start(). That’s it!
#include "thread.h"
using namespace Illuminate;
class MyThread : public Thread
{
private:
virtual void run() {}
};
int main()
{
MyThread thread;
thread.start(); // start the thread
thread.join(); // wait for the thread to complete
return 0;
}
Problems
The main current weakness of this class is the lack of thread safety, although there is unlikely to be problems in most suitations. A possible scenario which may cause problems is if the join() is called at the same time that the thread is completing as they both access the m_thread variable. The easiest way to get around this is through the use of locking, with which SDL supplies a simple interface for.
Conclusion
Well that’s it. A very simple class which allows a programmer to access some very advanced features. However it’s not all smooth sailing. Once you move down the path of threaded applications, you enter the realm of mutexes, which brings in a range of problems from deadlocking or worse!