C++11 Concurrency Tutorial
Anthony Williams
Just Software Solutions Ltd
http://www.justsoftwaresolutions.co.uk

28th April 2012
C++11 Concurrency Tutorial

Asynchronous tasks and
threads
Promises and tasks
Mutexes and condition
variables
Atomics
Anthony Williams
C++11 Concurrency Tutorial

Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
Spawning asynchronous tasks
Spawning asynchronous tasks

Two ways: std::async and
std::thread
It’s all about things that are
Callable:
Functions and Member functions
Objects with operator() and Lambda
functions
Anthony Williams
C++11 Concurrency Tutorial

Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
Hello World with std::async
#include <future> // for std::async
#include <iostream>
void write_message(std::string const& message) {
std::cout<<message;
}
int main() {
auto f=std::async(write_message,
"hello world from std::asyncn");
write_message("hello world from mainn");
f.wait();
}

Anthony Williams
C++11 Concurrency Tutorial

Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
Hello World with std::thread
#include <thread> // for std::thread
#include <iostream>
void write_message(std::string const& message) {
std::cout<<message;
}
int main() {
std::thread t(write_message,
"hello world from std::threadn");
write_message("hello world from mainn");
t.join();
}

Anthony Williams
C++11 Concurrency Tutorial

Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
Missing join with std::thread
#include <thread>
#include <iostream>
void write_message(std::string const& message) {
std::cout<<message;
}
int main() {
std::thread t(write_message,
"hello world from std::threadn");
write_message("hello world from mainn");
// oops no join
}

Anthony Williams
C++11 Concurrency Tutorial

Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
Missing wait with std::async
#include <future>
#include <iostream>
void write_message(std::string const& message) {
std::cout<<message;
}
int main() {
auto f=std::async(write_message,
"hello world from std::asyncn");
write_message("hello world from mainn");
// oops no wait
}

Anthony Williams
C++11 Concurrency Tutorial

Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
Async Launch Policies

The standard launch policies are the
members of the std::launch scoped
enum.
They can be used individually or together.

Anthony Williams
C++11 Concurrency Tutorial

Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
Async Launch Policies

std::launch::async => “as if” in a new
thread.
std::launch::deferred => executed on
demand.
std::launch::async |
std::launch::deferred =>
implementation chooses (default).

Anthony Williams
C++11 Concurrency Tutorial

Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
std::launch::async
#include <future>
#include <iostream>
#include <stdio.h>
void write_message(std::string const& message) {
std::cout<<message;
}
int main() {
auto f=std::async(
std::launch::async,write_message,
"hello world from std::asyncn");
write_message("hello world from mainn");
getchar(); f.wait();
}
Anthony Williams
C++11 Concurrency Tutorial

Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
std::launch::deferred
#include <future>
#include <iostream>
#include <stdio.h>
void write_message(std::string const& message) {
std::cout<<message;
}
int main() {
auto f=std::async(
std::launch::deferred,write_message,
"hello world from std::asyncn");
write_message("hello world from mainn");
getchar(); f.wait();
}
Anthony Williams
C++11 Concurrency Tutorial

Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
Returning values with std::async

#include <future>
#include <iostream>
int find_the_answer() {
return 42;
}
int main() {
auto f=std::async(find_the_answer);
std::cout<<"the answer is "<<f.get()<<"n";
}

Anthony Williams
C++11 Concurrency Tutorial

Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
Passing parameters
#include <future>
#include <iostream>
std::string copy_string(std::string const&s) {
return s;
}
int main() {
std::string s="hello";
auto f=std::async(std::launch::deferred,
copy_string,s);
s="goodbye";
std::cout<<f.get()<<" world!n";
}
Anthony Williams
C++11 Concurrency Tutorial

Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
Passing parameters with std::ref
#include <future>
#include <iostream>
std::string copy_string(std::string const&s) {
return s;
}
int main() {
std::string s="hello";
auto f=std::async(std::launch::deferred,
copy_string,std::ref(s));
s="goodbye";
std::cout<<f.get()<<" world!n";
}
Anthony Williams
C++11 Concurrency Tutorial

Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
Passing parameters with a lambda
std::string copy_string(std::string const&s) {
return s;
}
int main() {
std::string s="hello";
auto f=std::async(std::launch::deferred,
[&s](){return copy_string(s);});
s="goodbye";
std::cout<<f.get()<<" world!n";
}

Anthony Williams
C++11 Concurrency Tutorial

Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
std::async passes exceptions

#include <future>
#include <iostream>
int find_the_answer() {
throw std::runtime_error("Unable to find the answe
}
int main() {
auto f=std::async(find_the_answer);
try {
std::cout<<"the answer is "<<f.get()<<"n";
}
catch(std::runtime_error const& e) {
std::cout<<"nCaught exception: "<<e.what()<<std
}
}
Anthony Williams
C++11 Concurrency Tutorial

Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
Promises and Tasks
Manually setting futures

Two ways: std::promise and
std::packaged_task
std::promise allows you to explicitly set
the value
std::packaged_task is for manual task
invocation, e.g. thread pools.

Anthony Williams
C++11 Concurrency Tutorial

Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
std::promise
#include <future>
#include <thread>
#include <iostream>
void find_the_answer(std::promise<int>* p) {
p->set_value(42);
}
int main() {
std::promise<int> p;
auto f=p.get_future();
std::thread t(find_the_answer,&p);
std::cout<<"the answer is "<<f.get()<<"n";
t.join();
}
Anthony Williams
C++11 Concurrency Tutorial

Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
std::packaged_task
#include <future>
#include <thread>
#include <iostream>
int find_the_answer() {
return 42;
}
int main() {
std::packaged_task<int()> task(find_the_answer);
auto f=task.get_future();
std::thread t(std::move(task));
std::cout<<"the answer is "<<f.get()<<"n";
t.join();
}
Anthony Williams
C++11 Concurrency Tutorial

Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
Waiting for futures from multiple threads
Use std::shared_future<T> rather than
std::future<T>
std::future<int> f=/*...*/;
std::shared_future<int> sf(std::move(f));
std::future<int> f2=/*...*/;
std::shared_future<int> sf2(f.share());
std::promise<int> p;
std::shared_future<int> sf3(p.get_future());

Anthony Williams
C++11 Concurrency Tutorial

Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
#include <future>
#include <thread>
#include <iostream>
#include <sstream>
void wait_for_notify(int id,std::shared_future<int> sf)
std::ostringstream os;
os<<"Thread "<<id<<" waitingn";
std::cout<<os.str(); os.str("");
os<<"Thread "<<id<<" woken, val="<<sf.get()<<"n";
std::cout<<os.str();
}
int main() {
std::promise<int> p;
auto sf=p.get_future().share();
std::thread t1(wait_for_notify,1,sf);
std::thread t2(wait_for_notify,2,sf);
std::cout<<"Waitingn"; std::cin.get();
p.set_value(42);
t2.join(); t1.join();
}
std::shared_future<T> objects cannot be shared

Anthony Williams
C++11 Concurrency Tutorial

Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
Separate std::shared_future<T> objects can
share state

Anthony Williams
C++11 Concurrency Tutorial

Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
Mutexes and Condition Variables
Lower level synchronization

Locks and Mutexes
Condition variables

Anthony Williams
C++11 Concurrency Tutorial

Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
Mutexes

C++11 has 4 mutex classes:
std::mutex
std::recursive_mutex
std::timed_mutex
std::recursive_timed_mutex

Anthony Williams
C++11 Concurrency Tutorial

Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
Mutex operations (I)

Mutexes have 3 basic operations, which form
the Lockable concept:
m.lock()
m.try_lock()
m.unlock()

Anthony Williams
C++11 Concurrency Tutorial

Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
Mutex operations (II)

“Timed” mutexes have 2 additional operations.
A Lockable type that provides them satisfies
the TimedLockable concept.
m.try_lock_for(duration)
m.try_lock_until(time_point)

Anthony Williams
C++11 Concurrency Tutorial

Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
RAII lock templates

Locking and unlocking manually is error-prone,
especially in the face of exceptions.
C++11 provides RAII lock templates to make it
easier to get things right.
std::lock_guard does a simple lock and
unlock
std::unique_lock allows full control

Anthony Williams
C++11 Concurrency Tutorial

Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
std::mutex m;
void f(){
m.lock();
std::cout<<"In f()"<<std::endl;
m.unlock();
}
int main(){
m.lock();
std::thread t(f);
for(unsigned i=0;i<5;++i){
std::cout<<"In main()"<<std::endl;
std::this_thread::sleep_for(
std::chrono::seconds(1));
}
m.unlock();
t.join();
}
std::mutex m;
void f(){
std::lock_guard<std::mutex> guard(m);
std::cout<<"In f()"<<std::endl;
}
int main(){
m.lock();
std::thread t(f);
for(unsigned i=0;i<5;++i){
std::cout<<"In main()"<<std::endl;
std::this_thread::sleep_for(
std::chrono::seconds(1));
}
m.unlock();
t.join();
}
std::mutex m;
void f(int i){
std::unique_lock<std::mutex> guard(m);
std::cout<<"In f("<<i<<")"<<std::endl;
guard.unlock();
std::this_thread::sleep_for(
std::chrono::seconds(1));
guard.lock();
std::cout<<"In f("<<i<<") again"<<std::endl;
}
int main(){
std::unique_lock<std::mutex> guard(m);
std::thread t(f,1); std::thread t2(f,2);
std::cout<<"In main()"<<std::endl;
std::this_thread::sleep_for(
std::chrono::seconds(1));
guard.unlock();
t2.join(); t.join();
}
Locking multiple mutexes

class account
{
std::mutex m;
currency_value balance;
public:
friend void transfer(account& from,account& to,
currency_value amount)
{
std::lock_guard<std::mutex> lock_from(from.m
std::lock_guard<std::mutex> lock_to(to.m);
from.balance -= amount;
to.balance += amount;
}
};
Anthony Williams
C++11 Concurrency Tutorial

Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
Locking multiple mutexes (II)
void transfer(account& from,account& to,
currency_value amount)
{
std::lock(from.m,to.m);
std::lock_guard<std::mutex> lock_from(
from.m,std::adopt_lock);
std::lock_guard<std::mutex> lock_to(
to.m,std::adopt_lock);
from.balance -= amount;
to.balance += amount;
}

Anthony Williams
C++11 Concurrency Tutorial

Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
Waiting for events without futures

Repeatedly poll in a loop (busy-wait)
Wait using a condition variable

Anthony Williams
C++11 Concurrency Tutorial

Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
Waiting for an item
If all we’ve got is try_pop(), the only way to wait is to poll:
std::queue<my_class> the_queue;
std::mutex the_mutex;
void wait_and_pop(my_class& data) {
for(;;){
std::lock_guard<std::mutex> guard(the_mutex);
if(!the_queue.empty()) {
data=the_queue.front();
the_queue.pop();
return;
}
}
}
This is not ideal.
Anthony Williams
C++11 Concurrency Tutorial

Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
Performing a blocking wait
We want to wait for a particular condition to be true (there is an
item in the queue).
This is a job for std::condition_variable:
std::condition_variable the_cv;
void wait_and_pop(my_class& data) {
std::unique_lock<std::mutex> lk(the_mutex);
the_cv.wait(lk,
[]()
{return !the_queue.empty();});
data=the_queue.front();
the_queue.pop();
}
Anthony Williams
C++11 Concurrency Tutorial

Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
Signalling a waiting thread
To signal a waiting thread, we need to notify the condition
variable when we push an item on the queue:
void push(Data const& data)
{
{
std::lock_guard<std::mutex> lk(the_mutex);
the_queue.push(data);
}
the_cv.notify_one();
}

Anthony Williams
C++11 Concurrency Tutorial

Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
One-time Initialization
One-time initialization with std::call_once

std::unique_ptr<some_resource> resource_ptr;
std::once_flag resource_flag;
void foo()
{
std::call_once(resource_flag,[]{
resource_ptr.reset(new some_resource);
});
resource_ptr->do_something();
}

Anthony Williams
C++11 Concurrency Tutorial

Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
One-time initialization with local statics

void foo()
{
static some_resource resource;
resource.do_something();
}

Anthony Williams
C++11 Concurrency Tutorial

Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
Atomics
Atomic types

Sometimes mutexes and locks are too high level
This is where std::atomic<T> comes in
Lock-free for built-in types on popular platforms
Can use std::atomic<POD> — still lock-free for small
structs

Anthony Williams
C++11 Concurrency Tutorial

Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
Just::Thread

just::thread provides a complete implementation of the
C++11 thread library for MSVC and g++ on Windows, and g++
for Linux and MacOSX.

Anthony Williams
C++11 Concurrency Tutorial

Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
My Book

C++ Concurrency in Action:
Practical Multithreading with
the new C++ Standard.
http:
//stdthread.com/book

Anthony Williams
C++11 Concurrency Tutorial

Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk

C++11 concurrency

  • 1.
    C++11 Concurrency Tutorial AnthonyWilliams Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk 28th April 2012
  • 2.
    C++11 Concurrency Tutorial Asynchronoustasks and threads Promises and tasks Mutexes and condition variables Atomics Anthony Williams C++11 Concurrency Tutorial Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
  • 3.
  • 4.
    Spawning asynchronous tasks Twoways: std::async and std::thread It’s all about things that are Callable: Functions and Member functions Objects with operator() and Lambda functions Anthony Williams C++11 Concurrency Tutorial Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
  • 5.
    Hello World withstd::async #include <future> // for std::async #include <iostream> void write_message(std::string const& message) { std::cout<<message; } int main() { auto f=std::async(write_message, "hello world from std::asyncn"); write_message("hello world from mainn"); f.wait(); } Anthony Williams C++11 Concurrency Tutorial Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
  • 6.
    Hello World withstd::thread #include <thread> // for std::thread #include <iostream> void write_message(std::string const& message) { std::cout<<message; } int main() { std::thread t(write_message, "hello world from std::threadn"); write_message("hello world from mainn"); t.join(); } Anthony Williams C++11 Concurrency Tutorial Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
  • 7.
    Missing join withstd::thread #include <thread> #include <iostream> void write_message(std::string const& message) { std::cout<<message; } int main() { std::thread t(write_message, "hello world from std::threadn"); write_message("hello world from mainn"); // oops no join } Anthony Williams C++11 Concurrency Tutorial Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
  • 8.
    Missing wait withstd::async #include <future> #include <iostream> void write_message(std::string const& message) { std::cout<<message; } int main() { auto f=std::async(write_message, "hello world from std::asyncn"); write_message("hello world from mainn"); // oops no wait } Anthony Williams C++11 Concurrency Tutorial Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
  • 9.
    Async Launch Policies Thestandard launch policies are the members of the std::launch scoped enum. They can be used individually or together. Anthony Williams C++11 Concurrency Tutorial Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
  • 10.
    Async Launch Policies std::launch::async=> “as if” in a new thread. std::launch::deferred => executed on demand. std::launch::async | std::launch::deferred => implementation chooses (default). Anthony Williams C++11 Concurrency Tutorial Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
  • 11.
    std::launch::async #include <future> #include <iostream> #include<stdio.h> void write_message(std::string const& message) { std::cout<<message; } int main() { auto f=std::async( std::launch::async,write_message, "hello world from std::asyncn"); write_message("hello world from mainn"); getchar(); f.wait(); } Anthony Williams C++11 Concurrency Tutorial Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
  • 12.
    std::launch::deferred #include <future> #include <iostream> #include<stdio.h> void write_message(std::string const& message) { std::cout<<message; } int main() { auto f=std::async( std::launch::deferred,write_message, "hello world from std::asyncn"); write_message("hello world from mainn"); getchar(); f.wait(); } Anthony Williams C++11 Concurrency Tutorial Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
  • 13.
    Returning values withstd::async #include <future> #include <iostream> int find_the_answer() { return 42; } int main() { auto f=std::async(find_the_answer); std::cout<<"the answer is "<<f.get()<<"n"; } Anthony Williams C++11 Concurrency Tutorial Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
  • 14.
    Passing parameters #include <future> #include<iostream> std::string copy_string(std::string const&s) { return s; } int main() { std::string s="hello"; auto f=std::async(std::launch::deferred, copy_string,s); s="goodbye"; std::cout<<f.get()<<" world!n"; } Anthony Williams C++11 Concurrency Tutorial Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
  • 15.
    Passing parameters withstd::ref #include <future> #include <iostream> std::string copy_string(std::string const&s) { return s; } int main() { std::string s="hello"; auto f=std::async(std::launch::deferred, copy_string,std::ref(s)); s="goodbye"; std::cout<<f.get()<<" world!n"; } Anthony Williams C++11 Concurrency Tutorial Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
  • 16.
    Passing parameters witha lambda std::string copy_string(std::string const&s) { return s; } int main() { std::string s="hello"; auto f=std::async(std::launch::deferred, [&s](){return copy_string(s);}); s="goodbye"; std::cout<<f.get()<<" world!n"; } Anthony Williams C++11 Concurrency Tutorial Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
  • 17.
    std::async passes exceptions #include<future> #include <iostream> int find_the_answer() { throw std::runtime_error("Unable to find the answe } int main() { auto f=std::async(find_the_answer); try { std::cout<<"the answer is "<<f.get()<<"n"; } catch(std::runtime_error const& e) { std::cout<<"nCaught exception: "<<e.what()<<std } } Anthony Williams C++11 Concurrency Tutorial Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
  • 18.
  • 19.
    Manually setting futures Twoways: std::promise and std::packaged_task std::promise allows you to explicitly set the value std::packaged_task is for manual task invocation, e.g. thread pools. Anthony Williams C++11 Concurrency Tutorial Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
  • 20.
    std::promise #include <future> #include <thread> #include<iostream> void find_the_answer(std::promise<int>* p) { p->set_value(42); } int main() { std::promise<int> p; auto f=p.get_future(); std::thread t(find_the_answer,&p); std::cout<<"the answer is "<<f.get()<<"n"; t.join(); } Anthony Williams C++11 Concurrency Tutorial Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
  • 21.
    std::packaged_task #include <future> #include <thread> #include<iostream> int find_the_answer() { return 42; } int main() { std::packaged_task<int()> task(find_the_answer); auto f=task.get_future(); std::thread t(std::move(task)); std::cout<<"the answer is "<<f.get()<<"n"; t.join(); } Anthony Williams C++11 Concurrency Tutorial Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
  • 22.
    Waiting for futuresfrom multiple threads Use std::shared_future<T> rather than std::future<T> std::future<int> f=/*...*/; std::shared_future<int> sf(std::move(f)); std::future<int> f2=/*...*/; std::shared_future<int> sf2(f.share()); std::promise<int> p; std::shared_future<int> sf3(p.get_future()); Anthony Williams C++11 Concurrency Tutorial Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
  • 23.
    #include <future> #include <thread> #include<iostream> #include <sstream> void wait_for_notify(int id,std::shared_future<int> sf) std::ostringstream os; os<<"Thread "<<id<<" waitingn"; std::cout<<os.str(); os.str(""); os<<"Thread "<<id<<" woken, val="<<sf.get()<<"n"; std::cout<<os.str(); } int main() { std::promise<int> p; auto sf=p.get_future().share(); std::thread t1(wait_for_notify,1,sf); std::thread t2(wait_for_notify,2,sf); std::cout<<"Waitingn"; std::cin.get(); p.set_value(42); t2.join(); t1.join(); }
  • 24.
    std::shared_future<T> objects cannotbe shared Anthony Williams C++11 Concurrency Tutorial Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
  • 25.
    Separate std::shared_future<T> objectscan share state Anthony Williams C++11 Concurrency Tutorial Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
  • 26.
  • 27.
    Lower level synchronization Locksand Mutexes Condition variables Anthony Williams C++11 Concurrency Tutorial Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
  • 28.
    Mutexes C++11 has 4mutex classes: std::mutex std::recursive_mutex std::timed_mutex std::recursive_timed_mutex Anthony Williams C++11 Concurrency Tutorial Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
  • 29.
    Mutex operations (I) Mutexeshave 3 basic operations, which form the Lockable concept: m.lock() m.try_lock() m.unlock() Anthony Williams C++11 Concurrency Tutorial Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
  • 30.
    Mutex operations (II) “Timed”mutexes have 2 additional operations. A Lockable type that provides them satisfies the TimedLockable concept. m.try_lock_for(duration) m.try_lock_until(time_point) Anthony Williams C++11 Concurrency Tutorial Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
  • 31.
    RAII lock templates Lockingand unlocking manually is error-prone, especially in the face of exceptions. C++11 provides RAII lock templates to make it easier to get things right. std::lock_guard does a simple lock and unlock std::unique_lock allows full control Anthony Williams C++11 Concurrency Tutorial Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
  • 32.
    std::mutex m; void f(){ m.lock(); std::cout<<"Inf()"<<std::endl; m.unlock(); } int main(){ m.lock(); std::thread t(f); for(unsigned i=0;i<5;++i){ std::cout<<"In main()"<<std::endl; std::this_thread::sleep_for( std::chrono::seconds(1)); } m.unlock(); t.join(); }
  • 33.
    std::mutex m; void f(){ std::lock_guard<std::mutex>guard(m); std::cout<<"In f()"<<std::endl; } int main(){ m.lock(); std::thread t(f); for(unsigned i=0;i<5;++i){ std::cout<<"In main()"<<std::endl; std::this_thread::sleep_for( std::chrono::seconds(1)); } m.unlock(); t.join(); }
  • 34.
    std::mutex m; void f(inti){ std::unique_lock<std::mutex> guard(m); std::cout<<"In f("<<i<<")"<<std::endl; guard.unlock(); std::this_thread::sleep_for( std::chrono::seconds(1)); guard.lock(); std::cout<<"In f("<<i<<") again"<<std::endl; } int main(){ std::unique_lock<std::mutex> guard(m); std::thread t(f,1); std::thread t2(f,2); std::cout<<"In main()"<<std::endl; std::this_thread::sleep_for( std::chrono::seconds(1)); guard.unlock(); t2.join(); t.join(); }
  • 35.
    Locking multiple mutexes classaccount { std::mutex m; currency_value balance; public: friend void transfer(account& from,account& to, currency_value amount) { std::lock_guard<std::mutex> lock_from(from.m std::lock_guard<std::mutex> lock_to(to.m); from.balance -= amount; to.balance += amount; } }; Anthony Williams C++11 Concurrency Tutorial Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
  • 36.
    Locking multiple mutexes(II) void transfer(account& from,account& to, currency_value amount) { std::lock(from.m,to.m); std::lock_guard<std::mutex> lock_from( from.m,std::adopt_lock); std::lock_guard<std::mutex> lock_to( to.m,std::adopt_lock); from.balance -= amount; to.balance += amount; } Anthony Williams C++11 Concurrency Tutorial Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
  • 37.
    Waiting for eventswithout futures Repeatedly poll in a loop (busy-wait) Wait using a condition variable Anthony Williams C++11 Concurrency Tutorial Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
  • 38.
    Waiting for anitem If all we’ve got is try_pop(), the only way to wait is to poll: std::queue<my_class> the_queue; std::mutex the_mutex; void wait_and_pop(my_class& data) { for(;;){ std::lock_guard<std::mutex> guard(the_mutex); if(!the_queue.empty()) { data=the_queue.front(); the_queue.pop(); return; } } } This is not ideal. Anthony Williams C++11 Concurrency Tutorial Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
  • 39.
    Performing a blockingwait We want to wait for a particular condition to be true (there is an item in the queue). This is a job for std::condition_variable: std::condition_variable the_cv; void wait_and_pop(my_class& data) { std::unique_lock<std::mutex> lk(the_mutex); the_cv.wait(lk, []() {return !the_queue.empty();}); data=the_queue.front(); the_queue.pop(); } Anthony Williams C++11 Concurrency Tutorial Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
  • 40.
    Signalling a waitingthread To signal a waiting thread, we need to notify the condition variable when we push an item on the queue: void push(Data const& data) { { std::lock_guard<std::mutex> lk(the_mutex); the_queue.push(data); } the_cv.notify_one(); } Anthony Williams C++11 Concurrency Tutorial Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
  • 41.
  • 42.
    One-time initialization withstd::call_once std::unique_ptr<some_resource> resource_ptr; std::once_flag resource_flag; void foo() { std::call_once(resource_flag,[]{ resource_ptr.reset(new some_resource); }); resource_ptr->do_something(); } Anthony Williams C++11 Concurrency Tutorial Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
  • 43.
    One-time initialization withlocal statics void foo() { static some_resource resource; resource.do_something(); } Anthony Williams C++11 Concurrency Tutorial Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
  • 44.
  • 45.
    Atomic types Sometimes mutexesand locks are too high level This is where std::atomic<T> comes in Lock-free for built-in types on popular platforms Can use std::atomic<POD> — still lock-free for small structs Anthony Williams C++11 Concurrency Tutorial Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
  • 46.
    Just::Thread just::thread provides acomplete implementation of the C++11 thread library for MSVC and g++ on Windows, and g++ for Linux and MacOSX. Anthony Williams C++11 Concurrency Tutorial Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
  • 47.
    My Book C++ Concurrencyin Action: Practical Multithreading with the new C++ Standard. http: //stdthread.com/book Anthony Williams C++11 Concurrency Tutorial Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk