As C++ doesn’t have any native multi-threading support, you will need to rely on a system APIs to achieve multithreading. M$ has their own APIs, but I want to concentrate on the POSIX threading library as it is more widely compatible.
The Theory
So what does the POSIX threading APIs look like then? Well a bit of bad news first of all to C++ developers; these are C functions (doh!), the main one in question is:
pthread_create(pthread_t *handle, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg);
Nothing too scary looking, but as it takes a C function as the start_routine you may be wondering how on earth this could be integrated into a C++ member method? Well, that’s exactly what I’m going to show you now?!
The Code
Thread.hpp
#include <pthread.h>
class Thread {
public:
void start();
virtual void execute();
void wait_for_exit();
private:
pthread_t handle;
};
Here we have defined the Thread class, telling it to hold onto a POSIX thread instance in the field handle and also prototyping three methods:
- start, which will launch the new thread
- execute, which will contain the code to execute on the new thread
- wait_for_exit, which will join the thread to the main thread
Thread.cpp
#include <pthread.h>
#include <iostream>
#include "Thread.hpp"
using std::endl;
using std::clog;
extern "C"
{
// this C function will be used to receive the thread and pass it back to the Thread instance
void* thread_catch(void* arg) {
Thread* t = static_cast<Thread*>(arg);
t->execute();
return 0;
}
}
// method which starts the new thread
void Thread::start() {
pthread_create(&handle, 0, thread_catch, this);
}
// code which will be run on the new thread
void Thread::execute() {
clog << "Thread:Hello From a new Thread!" << endl;
}
// wait until this thread has finished executing
void Thread::wait_for_exit() {
pthread_join(handle, NULL);
}
The first thing you’ll notice is the C function thread_catch, this will be our C function which pthread_create will execute on the new thread, the argument will be the instance of the Thread class, so we can call it’s execute method.
The start function creates the POSIX thread and sends it the `this` pointer, so the C function can call execute on the correct instance.
wait_for_exit simply calls pthread_join which joins the main thread with this spawned thread, so the program doesn’t terminate before the thread has finished.
main.cpp
#include "Thread.hpp"
#include <pthread.h>
#include <iostream>
using std::cout;
using std::clog;
using std::endl;
class MyThread : public Thread {
public:
void execute();
int i;
};
void MyThread::execute() {
sleep(i);
cout << "Execute:" << i << endl;
}
int main() {
const int THREAD_COUNT = 3;
// create threads
MyThread t[THREAD_COUNT];
for (int i=THREAD_COUNT-1; i>=0; i--) { // start the threads in the opposite order to prove multi-threading
cout << "Start:" << i << endl;
t[i].i = i;
t[i].start();
}
// wait until all threads have finished
for (int i=0; i<THREAD_COUNT;i++) {
t[i].wait_for_exit();
}
return 0;
}
So what I’ve done here is to write a program that creates three instances of a derived Thread class which waits for x number of seconds. The program loops through the numbers 0-2 backwards, so they are instantiated in reverse. When the start method is called on the instance it spawns the Thread immediately, however the execute command makes the instance sleep for x seconds. This should all mean that the threads are instantiated in reverse order; but the cout in execute should be execute in the correct order. Here is the output:
Start:2
Start:1
Start:0
Execute:0
Execute:1
Execute:2
Compiling
The first trick is to find out where pthread.h is. On my Mac it’s on /usr/include/pthread.h but you can find it using:
locate pthread.h
So to compile the code use the following command:
g++ -o program Thread.cpp main.cpp /usr/include/pthread.h
If you would like to know more about pthread.h, check out this site.