In this article by Anton Polukhin Alekseevic, the author of the book Boost C++ Application Development Cookbook - Second Edition, we will see the multithreading concept.
Multithreading means multiple threads of execution exist within a single process. Threads may share process resources and have their own resources. Those threads of execution may run independently on different CPUs, leading to faster and more responsible programs.
Let's see how to create a thread of execution.
(For more resources related to this topic, see here.)
On modern multicore compilers, to achieve maximal performance (or just to provide a good user experience), programs usually must use multiple threads of execution. Here is a motivating example in which we need to create and fill a big file in a thread that draws the user interface:
#include <algorithm>
#include <fstream>
#include <iterator>
bool is_first_run();
// Function that executes for a long time.
void fill_file(char fill_char, std::size_t size, const char* filename);
// ...
// Somewhere in thread that draws a user interface:
if (is_first_run()) {
// This will be executing for a long time during which
// users interface freezes.
fill_file(0, 8 * 1024 * 1024, "save_file.txt");
}
This recipe requires knowledge of boost::bind or std::bind.
Starting a thread of execution never was so easy:
#include <boost/thread.hpp>
// ...
// Somewhere in thread that draws a user interface:
if (is_first_run()) {
boost::thread(boost::bind(
&fill_file,
0,
8 * 1024 * 1024,
"save_file.txt"
)).detach();
}
The boost::thread variable accepts a functional object that can be called without parameters (we provided one using boost::bind) and creates a separate thread of execution. That functional object is copied into a constructed thread of execution and run there.
After that, we call the detach() function, which does the following:
Note that without a call to detach(), the destructor of boost::thread will notice that it still holds a OS thread and will call std::terminate. std::terminate terminates our program without calling destructors, freeing up resources, and without other cleanup.
Default constructed threads also have a Not-A-Thread state, and they do not create a separate thread of execution.
What if we want to make sure that file was created and written before doing some other job? In that case we need to join the thread in the following way:
// ...
// Somewhere in thread that draws a user interface:
if (is_first_run()) {
boost::thread t(boost::bind(
&fill_file,
0,
8 * 1024 * 1024,
"save_file.txt"
));
// Do some work.
// ...
// Waiting for thread to finish.
t.join();
}
After the thread is joined, the boost::thread variable holds a Not-A-Thread state and its destructor does not call std::terminate.
With BOOST_THREAD_VERSION=2 defined, the destructor of boost::thread calls detach(), which does not lead to std::terminate. But doing so breaks compatibility with std::thread, and some day, when your project is moving to the C++ standard library threads or when BOOST_THREAD_VERSION=2 won't be supported; this will give you a lot of surprises. Version 4 of Boost.Thread is more explicit and strong, which is usually preferable in C++ language.
There is a very helpful wrapper that works as a RAII wrapper around the thread and allows you to emulate the BOOST_THREAD_VERSION=2 behavior; it is called boost::scoped_thread<T>, where T can be one of the following classes:
Here is a small example:
#include <boost/thread/scoped_thread.hpp>
void some_func();
void example_with_raii() {
boost::scoped_thread<boost::join_if_joinable> t(
boost::thread(&some_func)
);
// 't' will be joined at scope exit.
}
The boost::thread class was accepted as a part of the C++11 standard and you can find it in the <thread> header in the std:: namespace. There is no big difference between the Boost's version 4 and C++11 standard library versions of the thread class. However, boost::thread is available on the C++03 compilers, so its usage is more versatile.
We saw how to create a thread of execution using some easy techniques.
Further resources on this subject: