C++11 finally brings threading in to the core C++ language. Unfortunately, as my little investigation found, we’re not quite all there yet.
That’s okay though, ‘cause as it turns out, most of core function of C++ threading can be emulated using standard C and C++ features. While doing something else, I stumbled upon a library TinyThread++. It’s lightweight (2+1 source files), cross platform, and free+open source in the best ways possible.
http://tinythreadpp.bitsnbites.eu/
TinyThread++ attempts to emulate the usage of standard C++11 threading, in a decent, good enough, compromise way. I like it, so instead of fooling around with pThreads and whatever classic Microsoft APIs do, I’m going to use it. And since it’s so simple (2+1 files), if I need something or need to fix something, it’s right there. Great.
Alternatively, there is an equivalent C variant: http://tinycthread.bitsnbites.eu/
Construction and Basic Use
C++11 threads are quite advanced in how they construct. They take advantage of a variadic template for a clean simple syntax (think printf). You can find out more details here:
http://en.cppreference.com/w/cpp/thread/thread/thread
TinyThread++ thread construction is different, simpler, more C style. It uses a void*.
This isn’t so bad. Sure, it’s not as clean as a variadic template might make it (printf style, pass all arguments right to the construction call), but it gets the job done. The 2nd argument to thread’s construction is the same void* passed to the function. You could treat it as a pointer to something, casting to whatever argument pointer you like, or reinterpret it as a size_t (i.e. 32 or 64bit depending on the architecture).
The thread runs, and we halt what we’re doing in the main thread using the join call.
Herein, tthread::thread is functionally similar as std::thread. The complete reference is here:
http://en.cppreference.com/w/cpp/thread/thread
Notably is the idea of detachment [ t.detach() ] and testing if a thread is joinable [ t.joinable() ]. If a thread isn’t started (constructor w/o args), then you can’t join it. Or if a thread is explicitly detached, you can’t join it. Joinable is another way of knowing if the thread is running (with the sole exception of if you decide to detach it).
It is highly recommended you .join() a thread before destroying it (either through scope, or explicit delete calls).
Thread-local storage
Thread-local storage is a C++11 feature that has *almost* made its way everywhere. It’s been available since GCC 3.3 (MinGW ft GCC 4.x), and Visual C++ 2010. The only hold out is Clang, which is the compiler suite used by Xcode, Emscripten, and some other projects. However, as of Clang 3.2 it is available. Unfortunately, as of this writing, Clang 3.2 hasn’t been released yet. And if you’re an Apple developer, you need to wait for the next Xcode refresh where they update Clang. So literally, we are on the cusp of being able to use Thread-local storage everywhere! 6 months, give or take.
What this is is a special kind of global and static variable. Typical globals and statics are shared amongst all threads. Local storage types have a unique instance per thread.
Support for local storage types has been around for a long time now as the __thread or __declspec(thread) keywords. Further details can be found here:
http://en.wikipedia.org/wiki/Thread_local_storage#C.2B.2B
And the TinyThread++ version:
thread::hardware_concurrency()
This is a simple static function that tells you how many hardware threads are available. When porting TinyThread++ to new platforms (Marmalade), this will be a function that needs to be attended to. Also if the CPU supports Hyper Threading (Intel Atom), it will report 2 threads per core.
Will return 0 on failure (unknown number of cores).
this_thread
Instead of having to pass details about the current thread as arguments, several helper functions can be found in the global namespace this_thread. std::this_thread for C++11, and tthread::this_thread for TinyThread++.
http://en.cppreference.com/w/cpp/thread
TinyThread++ doesn’t support all of the this_thread features, but supports enough of them.
this_thread::yield()
When called from the current thread, it gives up the CPU until the other threads have had a chance to run.
this_thread::sleep_for( … )
When paired with the chrono library, you can put the current thread to sleep for a period of time.
Mutexes
Sure great, we can run and execute several threads of code, but without some sort of locking, we’re going to be smashing over each-others shared reads and writes. Hence mutex objects (Mutual Exclusion).
recursive_mutex
Hey guess what? If you call m.lock() on a regular mutex twice in a row, YOU DEADLOCK!
So instead, if you want to nest lock calls (and if you’re good about unlocking them), you can use a recursive_mutex type.
lock_guard
Locking (blocking) with mutexes is so common. How about a C++ class for locking and unlocking?
Condition Variable
The final part of TinyThread++ (C++11 std::thread has more parts).
condition_variable is an object that can use a mutex to broadcast a signal to one or all instances. It has a slightly unusual behavior, in that the mutex you pass it becomes unlocked while the condition_variable::wait() function blocks, then re-locks once it gets a notice (stops waiting). You can find a usage example here:
http://tinythreadpp.bitsnbites.eu/doc/classtthread_1_1condition__variable.html
TODO: Write a practical example. A manager thread that starts new job threads that die when they’re done? I dunno, I gotta brain-flex for a while to figure out something meaty.
Conclusion
No more Windows threads and pThreads! It’s about time C++ had a standard(ish) way of threading, that isn’t the 600 lb gorilla Boost.