2.5.7 Threads

What was the problem

Before C++11 there was just nothing in the standard library to execute a thread, so we had to either go native with pthreads, Windows threads, or whatever fit our need, or else we could use an independent library that would do the system abstraction for us, like Boost.Thread.

How the Problem is Solved

PIC <thread>

Thankfully, C++11 came with std::thread, which does the system abstraction for us and allows us to write portable threaded code8. Launching a thread is as simple as this:

auto expensive_computation = 
  []() -> void 
  { 
    // This infinite loop takes forever to complete! It slows down 
    // our awesome app, better put it in a thread. 
    while (true); 
  }; 
 
std::thread
t(expensive_computation); 
// Here we go, the thread is running.

PIC <mutex>, <condition_variable>

With the threads come the mutexes, condition variables, and more, that will help us write synchronization points. Here is a more complete example with two threads accessing shared data:

#include <cstdio> 
#include <mutex> 
#include <thread> 
 
struct flood_state 
{ 
  int counter; 
  std::mutex mutex; 
}; 
 
int main() 
{ 
  flood_state state; 
  state.counter = 0; 
 
  // std::thread’s constructor takes the function to be executed in the thread 
  // as its argument. Here we use a lambda [2.1.7]. 
  std::thread increase 
    ([&state]() -> void 
     { 
       while (true) 
         { 
           // Wait until the mutex is available and lock it.  std::unique_lock 
           // automatically unlocks it when going out of scope. Good old RAII. 
           const std::unique_lock<std::mutex> lock(state.mutex); 
           ++state.counter; 
         } 
     }); 
  std::thread decrease 
    ([&state]() -> void 
     { 
       while (true) 
         { 
           int counter; 
 
           { 
             // We limit the scope of the lock to the access to the shared 
             // state. 
             std::unique_lock<std::mutex> lock(state.mutex); 
             counter = state.counter; 
             state.counter -= 2; 
           } 
 
           // This is executed after the release of the mutex, so the state can 
           // be accessed while printing. 
           printf("%d\n", counter); 
         } 
     }); 
 
  // std::thread::join() waits until the thread is over (which will not happen 
  // in our case as nothing breaks outside the infinite loops. 
  increase.join(); 
  decrease.join(); 
 
  return 0; 
}

8When the targeted platform supports it. I’m looking at you WebAssembly!