C++ Threads Using boost::thread in 5 Minutes
This post is the first in the new "5 Minute" series. Each post is accompanied by a 5min tutorial video on YouTube. I realized when looking for YouTube tutorials that I gravitate towards the 5 minute videos rather than the longer ones. I'm usually looking for a specific technique or approach, and I've found that I can usually get what I need (or at least enough so I can Google the rest) in a short time. So here goes.
Essentials for boost::threads
||A header file with the necessary declarations.|
||A container with which to manage the thread(s).|
||A function object to launch the thread.|
||Wait for the threads to complete and clean up.|
Below is the original version of the file that runs thing sequentially. Notice that it sings the first song, "Row, Row, Row Your Boat" completely using a free function, then it sings the second song, "I'm a Little Teapot", using a class member function. For the serial version the difference is gratuitous, but it sets the stage to demonstrate running a free function in a thread compared to running a member function in a thread.
Take notice of the calls to
teapotSinger.perform() and their respective definitions, as these are what will run in threads in the revised code.
[crayon url="2012/05/thread_quickstart_orig.cpp" lang="cpp"/]
The changes to thread the code are pretty small. We create a container for the threads with
boost::thread_group tgroup;. I prefer to use
thread_group unless I need specific functionality that is only available with a
boost::thread, e.g. the ability to interrupt an individual thread. The
thread_group has one really great feature:
join_all() which waits for the threads to complete in any order. When you use
boost::thread, you are responsible to shut them down and wait in the correct order: sometimes that is straightforward, and sometimes that is difficult.
Launching the Thread
To launch the thread, use
boost::thread_group::create_thread() and provide a function object as an argument. I always use
boost::bind to create the function object. (
boost::bind is the best thing since sliced bread; we'll cover it in another time.) The Boost documentation claims that the use of
boost::bind is unnecessary - that hasn't been my experience.
The first argument to
boost::bind is either a function pointer or a member function pointer, or a C++11 lambda. If it is a member function pointer, then the next argument must be a pointer to an instance of the class. Note that
static member functions are treated like functions rather than member functions. All arguments, including default arguments, must be explicitly supplied. Note that this process uses value semantics. If a type does not have value semantics, e.g.
std::osteam, then the
boost::ref library is helpful.
The thread is running when
create_thread returns. It runs from beginning to end of the function object passed to
create_thread. For clean shutdown and to allow threads time to complete their work, you must join the thread. This is where the use of
thread_group is helpful, because it provides
join_all, which waits for the threads to complete in any order and does not return until all threads have joined.
Really, getting started with threads wasn't as difficult as you thought, eh?
[crayon url="2012/05/thread_quickstart.cpp" lang="cpp"]