Some people like to wrap everything into C++ classes, including threads. There is some intricate danger in wrapping a resource around a C++ object because the C++ object gives you the impression that the resource can be aliased (i.e. it is okay to have multiple pointers/references to the same object) when it is not. Also, since you're not allowed to peek inside the internal state of the object, the user may call object methods in an order that violates object consistency and produce undefined result. In the worst case, it may cause leakage of scarce resources like processes, file descriptors, and network sockets. Object-oriented encapsulation takes away your ability to reason about resource usage.
For example, suppose you write a C++ Mutex class to wrap around pthread mutex. What if the destructor is called when the mutex is still locked?
In the code I attach below, the Thread class represents a pthread. It has a start() method that begins execution of some threaded code and a join() method to wait until the thread finishes. What if start() is called twice on the same object? (Answer: the previous thread could be orphaned and we lose a reference to it while it's still running). What if the C++ object is destructed while a thread is still running? (Answer: the operating system wouldn't be able to properly clean-up the thread, such as freeing its run-time stack, which can be as large as 4MB). The example code I attach below tries to deal with these issues by doing lots of run-time checks. The run-time checks is what gives the impression that C++ is bloated.
Having warned you with all that, the code I attach below is tested to work on g++ (The C++ compiler in GCC) with -Wall.