c++11 concurrency - github · agenda • high-level components • low-level lock-based components...

184
C++11 Concurrency 1 Tuesday, May 15, 12

Upload: others

Post on 08-Aug-2020

0 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

C++11 Concurrency

1

Tuesday, May 15, 12

Page 2: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

Agenda

• High-level components

• Low-level lock-based components

2

Tuesday, May 15, 12

Page 3: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

It’s a standard!

3

• The technology may be old, but having it as an international standard is brand new

• More portable code

• Common facilities

Tuesday, May 15, 12

Page 4: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

High-Level Components

4

Tuesday, May 15, 12

Page 5: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

std::thread

5

Tuesday, May 15, 12

Page 6: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

#include <thread>

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){ std::string greet = french["hello"]; std::thread t( [&]{std::cout << greet << ", ";} );

std::string audience = french["world"]; t.join(); std::cout << audience << std::endl;}

Hello, World(en Français)

6

Tuesday, May 15, 12

Page 7: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

#include <thread>

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){ std::string greet = french["hello"]; std::thread t( [&]{std::cout << greet << ", ";} );

std::string audience = french["world"]; t.join(); std::cout << audience << std::endl;}

Hello, World(en Français)

6

French to English Dictionary

Tuesday, May 15, 12

Page 8: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

#include <thread>

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){ std::string greet = french["hello"]; std::thread t( [&]{std::cout << greet << ", ";} );

std::string audience = french["world"]; t.join(); std::cout << audience << std::endl;}

Hello, World(en Français)

6

Look up the greeting

Tuesday, May 15, 12

Page 9: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

#include <thread>

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){ std::string greet = french["hello"]; std::thread t( [&]{std::cout << greet << ", ";} );

std::string audience = french["world"]; t.join(); std::cout << audience << std::endl;}

Hello, World(en Français)

6

time-consuming I/O

Tuesday, May 15, 12

Page 10: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

#include <thread>

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){ std::string greet = french["hello"]; std::thread t( [&]{std::cout << greet << ", ";} );

std::string audience = french["world"]; t.join(); std::cout << audience << std::endl;}

Hello, World(en Français)

6

time-consuming I/O

next lookup

Tuesday, May 15, 12

Page 11: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

#include <thread>

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){ std::string greet = french["hello"]; std::thread t( [&]{std::cout << greet << ", ";} );

std::string audience = french["world"]; t.join(); std::cout << audience << std::endl;}

Hello, World(en Français)

6

time-consuming I/O

wait for I/O to complete

Tuesday, May 15, 12

Page 12: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

#include <thread>

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){ std::string greet = french["hello"]; std::thread t( [&]{std::cout << greet << ", ";} );

std::string audience = french["world"]; t.join(); std::cout << audience << std::endl;}

Hello, World(en Français)

6

wait for I/O to complete

Tuesday, May 15, 12

Page 13: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

#include <thread>

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){ std::string greet = french["hello"]; std::thread t( [&]{std::cout << greet << ", ";} );

std::string audience = french["world"]; t.join(); std::cout << audience << std::endl;}

Hello, World(en Français)

6

It's a wrap!

Tuesday, May 15, 12

Page 14: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

#include <thread>

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){ std::string greet = french["hello"]; std::thread t( [&]{std::cout << greet << ", ";} );

std::string audience = french["world"]; t.join(); std::cout << audience << std::endl;}

Hello, World(en Français)

6

Tuesday, May 15, 12

Page 15: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

#include <thread>

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){ std::string greet = french["hello"]; std::thread t( [&]{std::cout << greet << ", ";} );

std::string audience = french["world"]; t.join(); std::cout << audience << std::endl;}

Hello, World(en Français)

7

Tuesday, May 15, 12

Page 16: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

#include <thread>

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){ std::string greet = french["hello"]; std::thread t( [](std::string const& x){std::cout << x << ", ";}, std::ref(greet) ); std::string audience = french["world"]; t.join(); std::cout << audience << std::endl;}

Hello, World(en Français)

8

Tuesday, May 15, 12

Page 17: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

#include <thread>

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){ std::string greet = french["hello"]; std::thread t( [](std::string const& x){std::cout << x << ", ";}, std::ref(greet) ); std::string audience = french["world"]; t.join(); std::cout << audience << std::endl;}

Hello, World(en Français)

8

Uses std::bind() protocol

Tuesday, May 15, 12

Page 18: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

#include <thread>

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){ std::string greet = french["hello"]; std::thread t( [](std::string const& x){std::cout << x << ", ";}, std::ref(greet) ); std::string audience = french["world"]; t.join(); std::cout << audience << std::endl;}

Hello, World(en Français)

8

Tuesday, May 15, 12

Page 19: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

struct thread { thread() noexcept; template <class F, class ...Args> explicit thread(F&& f, Args&&... args); ~thread();

void swap(thread&) noexcept; thread(thread&&) noexcept; thread& operator=(thread&&) noexcept; thread(const thread&) = delete; thread& operator=(const thread&) = delete;

bool joinable() const noexcept; void join(); void detach();

std::thread

9

Tuesday, May 15, 12

Page 20: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

struct thread { thread() noexcept; template <class F, class ...Args> explicit thread(F&& f, Args&&... args); ~thread();

void swap(thread&) noexcept; thread(thread&&) noexcept; thread& operator=(thread&&) noexcept; thread(const thread&) = delete; thread& operator=(const thread&) = delete;

bool joinable() const noexcept; void join(); void detach();

std::thread

9

Move-only

Tuesday, May 15, 12

Page 21: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

struct thread { thread() noexcept; template <class F, class ...Args> explicit thread(F&& f, Args&&... args); ~thread();

void swap(thread&) noexcept; thread(thread&&) noexcept; thread& operator=(thread&&) noexcept; thread(const thread&) = delete; thread& operator=(const thread&) = delete;

bool joinable() const noexcept; void join(); void detach();

std::thread

9

Tuesday, May 15, 12

Page 22: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

struct thread { thread() noexcept; template <class F, class ...Args> explicit thread(F&& f, Args&&... args); ~thread(); bool joinable() const noexcept; void join(); void detach(); static unsigned hardware_concurrency() noexcept; class id; id get_id() const noexcept; typedef unspeci!ed native_handle_type; native_handle_type native_handle();};

std::thread

10

Move-only

Tuesday, May 15, 12

Page 23: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

move-onlystruct thread { thread() noexcept; template <class F, class ...Args> explicit thread(F&& f, Args&&... args); ~thread(); bool joinable() const noexcept; void join(); void detach(); static unsigned hardware_concurrency() noexcept; class id; id get_id() const noexcept; typedef unspeci!ed native_handle_type; native_handle_type native_handle();};

std::thread

10

We’ll abbreviate it like this

Tuesday, May 15, 12

Page 24: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

move-onlystruct thread { thread() noexcept; template <class F, class ...Args> explicit thread(F&& f, Args&&... args); ~thread(); bool joinable() const noexcept; void join(); void detach(); static unsigned hardware_concurrency() noexcept; class id; id get_id() const noexcept; typedef unspeci!ed native_handle_type; native_handle_type native_handle();};

std::thread

10

Tuesday, May 15, 12

Page 25: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

What's Not Here

11

• Thread priorities

• Scheduling control

• Other OS-speci!c details

• Use the native_handle() for these things if you need them

Tuesday, May 15, 12

Page 26: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

• a joinable() thread has a non-default id

• Must be joinable() when:

• join()ed

• detach()ed

• Must not be joinable() when:

• destroyed

• move-assigned

joinability

12

Tuesday, May 15, 12

Page 27: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

• a joinable() thread has a non-default id

• Must be joinable() when:

• join()ed

• detach()ed

• Must not be joinable() when:

• destroyed

• move-assigned

joinability

12

The wages of joinability is…

Tuesday, May 15, 12

Page 28: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

• a joinable() thread has a non-default id

• Must be joinable() when:

• join()ed

• detach()ed

• Must not be joinable() when:

• destroyed

• move-assigned

joinability

12

The wages of joinability is…terminate()!

Tuesday, May 15, 12

Page 29: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

• a joinable() thread has a non-default id

• Must be joinable() when:

• join()ed

• detach()ed

• Must not be joinable() when:

• destroyed

• move-assigned

joinability

12

Tuesday, May 15, 12

Page 30: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

• Threading operations throw system_error

• Thread launch may throw if system resources are used up

• detach() and join() will throw if

• the thread is not joinable()

• deadlock is detected (join only)

• Thread functions must not leak exceptions

Exceptions

13

Tuesday, May 15, 12

Page 31: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

• Threading operations throw system_error

• Thread launch may throw if system resources are used up

• detach() and join() will throw if

• the thread is not joinable()

• deadlock is detected (join only)

• Thread functions must not leak exceptions

Exceptions

13

The wages of exceptional

thread exit is…

Tuesday, May 15, 12

Page 32: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

• Threading operations throw system_error

• Thread launch may throw if system resources are used up

• detach() and join() will throw if

• the thread is not joinable()

• deadlock is detected (join only)

• Thread functions must not leak exceptions

Exceptions

13

The wages of exceptional

thread exit is…terminate()!

Tuesday, May 15, 12

Page 33: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

• Threading operations throw system_error

• Thread launch may throw if system resources are used up

• detach() and join() will throw if

• the thread is not joinable()

• deadlock is detected (join only)

• Thread functions must not leak exceptions

Exceptions

13

Tuesday, May 15, 12

Page 34: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

#include <thread>

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){ std::string greet = french["hello"]; std::thread t( [&]{std::cout << greet << ", ";} ); try { std::string audience = french["world"]; } catch(...) { t.join(); throw; } t.join(); std::cout << audience << std::endl;}

Hello, World(en Français)

14

Tuesday, May 15, 12

Page 35: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

#include <thread>

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){ std::string greet = french["hello"]; std::thread t( [&]{std::cout << greet << ", ";} ); try { std::string audience = french["world"]; } catch(...) { t.join(); throw; } t.join(); std::cout << audience << std::endl;}

Hello, World(en Français)

14

preventing termination

Tuesday, May 15, 12

Page 36: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

#include <thread>

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){ std::string greet = french["hello"]; std::thread t( [&]{std::cout << greet << ", ";} ); try { std::string audience = french["world"]; } catch(...) { t.join(); throw; } t.join(); std::cout << audience << std::endl;}

Hello, World(en Français)

14

Uhh…

Tuesday, May 15, 12

Page 37: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

#include <thread>

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){ std::string greet = french["hello"]; std::thread t( [&]{std::cout << greet << ", ";} ); try { std::string audience = french["world"]; } catch(...) { t.join(); throw; } t.join(); std::cout << audience << std::endl;}

Hello, World(en Français)

14

Tuesday, May 15, 12

Page 38: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

namespace this_thread{ thread::id get_id() noexcept; void yield() noexcept; template <class Clock, class Duration> void sleep_until( const chrono::time_point<Clock,Duration>& abs_time); template <class Rep, class Period> void sleep_for( const chrono::duration<Rep,Period>& rel_time);}

this_thread

15

Tuesday, May 15, 12

Page 39: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

namespace this_thread{ thread::id get_id() noexcept; void yield() noexcept; template <class Clock, class Duration> void sleep_until( const chrono::time_point<Clock,Duration>& abs_time); template <class Rep, class Period> void sleep_for( const chrono::duration<Rep,Period>& rel_time);}

this_thread

15

This pattern repeats

Tuesday, May 15, 12

Page 40: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

namespace this_thread{ thread::id get_id() noexcept; void yield() noexcept; template <class Clock, class Duration> void sleep_until( const chrono::time_point<Clock,Duration>& abs_time); template <class Rep, class Period> void sleep_for( const chrono::duration<Rep,Period>& rel_time);}

this_thread

15

Tuesday, May 15, 12

Page 41: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

namespace this_thread{ thread::id get_id() noexcept; void yield() noexcept;

void sleep_until( time_point );

void sleep_for( duration );

}

this_thread

16

Tuesday, May 15, 12

Page 42: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

namespace this_thread{ thread::id get_id() noexcept; void yield() noexcept;

void sleep_until( time_point );

void sleep_for( duration );

}

this_thread

16

We’ll abbreviate it like this

Tuesday, May 15, 12

Page 43: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

namespace this_thread{ thread::id get_id() noexcept; void yield() noexcept;

void sleep_until( time_point );

void sleep_for( duration );

}

this_thread

16

Tuesday, May 15, 12

Page 44: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

std::asyncand

std::future

17

Tuesday, May 15, 12

Page 45: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

#include <thread>

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){ std::string greet = french["hello"]; std::thread t( [&]{std::cout << greet << ", ";} ); try { std::string audience = french["world"]; } catch(...) { t.join(); throw; } t.join(); std::cout << audience << std::endl;}

Hello, World(en Français)

18

Tuesday, May 15, 12

Page 46: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

#include <thread>

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){ std::string greet = french["hello"]; std::thread t( [&]{std::cout << greet << ", ";} ); try { std::string audience = french["world"]; } catch(...) { t.join(); throw; } t.join(); std::cout << audience << std::endl;}

Hello, World(en Français)

18

preventing termination

Tuesday, May 15, 12

Page 47: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

#include <thread>

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){ std::string greet = french["hello"]; std::thread t( [&]{std::cout << greet << ", ";} ); try { std::string audience = french["world"]; } catch(...) { t.join(); throw; } t.join(); std::cout << audience << std::endl;}

Hello, World(en Français)

18

Uhh…

Tuesday, May 15, 12

Page 48: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

#include <thread>

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){ std::string greet = french["hello"]; std::thread t( [&]{std::cout << greet << ", ";} ); try { std::string audience = french["world"]; } catch(...) { t.join(); throw; } t.join(); std::cout << audience << std::endl;}

Hello, World(en Français)

18

Tuesday, May 15, 12

Page 49: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

#include <future>

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){ std::string greet = french["hello"]; auto f = std::async([&]{std::cout << greet << ", ";} );

std::string audience = french["world"]; f.get(); std::cout << audience << std::endl;}

A Better Approach

19

Tuesday, May 15, 12

Page 50: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

#include <future>

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){ std::string greet = french["hello"]; auto f = std::async([&]{std::cout << greet << ", ";} );

std::string audience = french["world"]; f.get(); std::cout << audience << std::endl;}

A Better Approach

19

Look up the greeting

Tuesday, May 15, 12

Page 51: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

#include <future>

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){ std::string greet = french["hello"]; auto f = std::async([&]{std::cout << greet << ", ";} );

std::string audience = french["world"]; f.get(); std::cout << audience << std::endl;}

A Better Approach

19

time-consuming I/O

Tuesday, May 15, 12

Page 52: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

#include <future>

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){ std::string greet = french["hello"]; auto f = std::async([&]{std::cout << greet << ", ";} );

std::string audience = french["world"]; f.get(); std::cout << audience << std::endl;}

A Better Approach

19

time-consuming I/O

next lookup

Tuesday, May 15, 12

Page 53: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

#include <future>

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){ std::string greet = french["hello"]; auto f = std::async([&]{std::cout << greet << ", ";} );

std::string audience = french["world"]; f.get(); std::cout << audience << std::endl;}

A Better Approach

19

time-consuming I/O

wait for I/O to complete

Tuesday, May 15, 12

Page 54: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

#include <future>

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){ std::string greet = french["hello"]; auto f = std::async([&]{std::cout << greet << ", ";} );

std::string audience = french["world"]; f.get(); std::cout << audience << std::endl;}

A Better Approach

19

wait for I/O to complete

Tuesday, May 15, 12

Page 55: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

#include <future>

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){ std::string greet = french["hello"]; auto f = std::async([&]{std::cout << greet << ", ";} );

std::string audience = french["world"]; f.get(); std::cout << audience << std::endl;}

A Better Approach

19

Tuesday, May 15, 12

Page 56: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

#include <future>

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){ std::string greet = french["hello"]; std::future<void> f = std::async( [&]{std::cout << greet << ", ";} ); std::string audience = french["world"]; f.get(); std::cout << audience << std::endl;}

A Better Approach

20

Tuesday, May 15, 12

Page 57: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

#include <future>

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){ std::string greet = french["hello"]; std::future<void> f = std::async( [&]{std::cout << greet << ", ";} ); std::string audience = french["world"]; f.get(); std::cout << audience << std::endl;}

“retrieve” the (void) value…

A Better Approach

20

Tuesday, May 15, 12

Page 58: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

#include <future>

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){ std::string greet = french["hello"]; std::future<void> f = std::async( [&]{std::cout << greet << ", ";} ); std::string audience = french["world"]; f.get(); std::cout << audience << std::endl;}

“retrieve” the (void) value……or rethrow the exception

A Better Approach

20

Tuesday, May 15, 12

Page 59: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

#include <future>

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){ std::string greet = french["hello"]; std::future<void> f = std::async( [&]{std::cout << greet << ", ";} ); std::string audience = french["world"]; f.get(); std::cout << audience << std::endl;}

A Better Approach

20

Tuesday, May 15, 12

Page 60: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

#include <future>

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){ auto greet = std::async([]{ return french["hello"]; });

std::string audience = french["world"]; std::cout << greet.get() << ", " << audience << std::endl;}

std::future Values

21

Tuesday, May 15, 12

Page 61: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

#include <future>

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){ auto greet = std::async([]{ return french["hello"]; });

std::string audience = french["world"]; std::cout << greet.get() << ", " << audience << std::endl;}

std::future Values

21

std::future<std::string>

Tuesday, May 15, 12

Page 62: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

#include <future>

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){ auto greet = std::async([]{ return french["hello"]; });

std::string audience = french["world"]; std::cout << greet.get() << ", " << audience << std::endl;}

std::future Values

21

retrieve the string value

Tuesday, May 15, 12

Page 63: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

#include <future>

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){ auto greet = std::async([]{ return french["hello"]; });

std::string audience = french["world"]; std::cout << greet.get() << ", " << audience << std::endl;}

std::future Values

21

Tuesday, May 15, 12

Page 64: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

enum class launch : unspecified // a bitmask type{ async = unspecified, // asynchronous, in a thread deferred = unspecified, // synchronous, on demand implementation-defined // your vendor's stuff here};

async Launch Policy

22

Tuesday, May 15, 12

Page 65: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

enum class launch : unspecified // a bitmask type{ async = unspecified, // asynchronous, in a thread deferred = unspecified, // synchronous, on demand implementation-defined // your vendor's stuff here};

async Launch Policy

22

“async | deferred” is the default. It means, “asynchronous if there’s parallelism to be had”……but GCC’s libstdc++ just treats it like deferred

Tuesday, May 15, 12

Page 66: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

enum class launch : unspecified // a bitmask type{ async = unspecified, // asynchronous, in a thread deferred = unspecified, // synchronous, on demand implementation-defined // your vendor's stuff here};

async Launch Policy

22

“async | deferred” is the default. It means, “asynchronous if there’s parallelism to be had”……but GCC’s libstdc++ just treats it like deferred

(see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51617)

Tuesday, May 15, 12

Page 67: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <class Iter>void parallel_merge_sort(Iter start, Iter finish) { std::size_t d = std::distance(start, finish); if (d <= 1) return; Iter mid = start; std::advance(mid, d/2); auto f = std::async( d < 768 ? std::launch::deferred : std::launch::deferred | std::launch::async [=]{ parallel_merge_sort(start,mid); }); parallel_merge_sort(mid,finish); f.get(); std::inplace_merge(start,mid,finish);}

Using Launch Policies

23

Tuesday, May 15, 12

Page 68: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <class Iter>void parallel_merge_sort(Iter start, Iter finish) { std::size_t d = std::distance(start, finish); if (d <= 1) return; Iter mid = start; std::advance(mid, d/2); auto f = std::async( d < 768 ? std::launch::deferred : std::launch::deferred | std::launch::async [=]{ parallel_merge_sort(start,mid); }); parallel_merge_sort(mid,finish); f.get(); std::inplace_merge(start,mid,finish);}

Using Launch Policies

23

divide

Tuesday, May 15, 12

Page 69: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <class Iter>void parallel_merge_sort(Iter start, Iter finish) { std::size_t d = std::distance(start, finish); if (d <= 1) return; Iter mid = start; std::advance(mid, d/2); auto f = std::async( d < 768 ? std::launch::deferred : std::launch::deferred | std::launch::async [=]{ parallel_merge_sort(start,mid); }); parallel_merge_sort(mid,finish); f.get(); std::inplace_merge(start,mid,finish);}

Using Launch Policies

23

conquerconquer

Tuesday, May 15, 12

Page 70: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <class Iter>void parallel_merge_sort(Iter start, Iter finish) { std::size_t d = std::distance(start, finish); if (d <= 1) return; Iter mid = start; std::advance(mid, d/2); auto f = std::async( d < 768 ? std::launch::deferred : std::launch::deferred | std::launch::async [=]{ parallel_merge_sort(start,mid); }); parallel_merge_sort(mid,finish); f.get(); std::inplace_merge(start,mid,finish);}

Using Launch Policies

23

unify

Tuesday, May 15, 12

Page 71: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <class Iter>void parallel_merge_sort(Iter start, Iter finish) { std::size_t d = std::distance(start, finish); if (d <= 1) return; Iter mid = start; std::advance(mid, d/2); auto f = std::async( d < 768 ? std::launch::deferred : std::launch::deferred | std::launch::async [=]{ parallel_merge_sort(start,mid); }); parallel_merge_sort(mid,finish); f.get(); std::inplace_merge(start,mid,finish);}

Using Launch Policies

23

handle short sequences synchronously

Tuesday, May 15, 12

Page 72: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <class Iter>void parallel_merge_sort(Iter start, Iter finish) { std::size_t d = std::distance(start, finish); if (d <= 1) return; Iter mid = start; std::advance(mid, d/2); auto f = std::async( d < 768 ? std::launch::deferred : std::launch::deferred | std::launch::async [=]{ parallel_merge_sort(start,mid); }); parallel_merge_sort(mid,finish); f.get(); std::inplace_merge(start,mid,finish);}

Using Launch Policies

23

use available threads for

longer sequences

Tuesday, May 15, 12

Page 73: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <class Iter>void parallel_merge_sort(Iter start, Iter finish) { std::size_t d = std::distance(start, finish); if (d <= 1) return; Iter mid = start; std::advance(mid, d/2); auto f = std::async( d < 768 ? std::launch::deferred : std::launch::deferred | std::launch::async [=]{ parallel_merge_sort(start,mid); }); parallel_merge_sort(mid,finish); f.get(); std::inplace_merge(start,mid,finish);}

Using Launch Policies

23

Tuesday, May 15, 12

Page 74: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

enum class future_status { ready, timeout, deferred };

template <class R> struct future { future() noexcept; bool valid() const noexcept;

R get();

void wait() const; future_status wait_for( duration ) const; future_status wait_until( time_point ) const;

shared_future<R> share();};

std::future

24

move-only

Tuesday, May 15, 12

Page 75: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

enum class future_status { ready, timeout, deferred };

template <class R> struct future { future() noexcept; bool valid() const noexcept;

R get();

void wait() const; future_status wait_for( duration ) const; future_status wait_until( time_point ) const;

shared_future<R> share();};

std::future

24

move-only

valid() ⇔ there is, or will be, a result we can get()

Tuesday, May 15, 12

Page 76: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

enum class future_status { ready, timeout, deferred };

template <class R> struct future { future() noexcept; bool valid() const noexcept;

R get();

void wait() const; future_status wait_for( duration ) const; future_status wait_until( time_point ) const;

shared_future<R> share();};

std::future

24

move-only

one-shot! afterwards, valid() == false

Tuesday, May 15, 12

Page 77: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

enum class future_status { ready, timeout, deferred };

template <class R> struct future { future() noexcept; bool valid() const noexcept;

R get();

void wait() const; future_status wait_for( duration ) const; future_status wait_until( time_point ) const;

shared_future<R> share();};

std::future

24

move-only

wait for “ready” state

Tuesday, May 15, 12

Page 78: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

enum class future_status { ready, timeout, deferred };

template <class R> struct future { future() noexcept; bool valid() const noexcept;

R get();

void wait() const; future_status wait_for( duration ) const; future_status wait_until( time_point ) const;

shared_future<R> share();};

std::future

24

move-only

timed wait, for the impatient

Tuesday, May 15, 12

Page 79: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

enum class future_status { ready, timeout, deferred };

template <class R> struct future { future() noexcept; bool valid() const noexcept;

R get();

void wait() const; future_status wait_for( duration ) const; future_status wait_until( time_point ) const;

shared_future<R> share();};

std::future

24

move-only

timed wait, for the impatient

Tuesday, May 15, 12

Page 80: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

enum class future_status { ready, timeout, deferred };

template <class R> struct future { future() noexcept; bool valid() const noexcept;

R get();

void wait() const; future_status wait_for( duration ) const; future_status wait_until( time_point ) const;

shared_future<R> share();};

std::future

24

move-only

upgrade *this to multi-shot, copyable

Tuesday, May 15, 12

Page 81: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

enum class future_status { ready, timeout, deferred };

template <class R> struct future { future() noexcept; bool valid() const noexcept;

R get();

void wait() const; future_status wait_for( duration ) const; future_status wait_until( time_point ) const;

shared_future<R> share();};

std::future

24

move-only

Tuesday, May 15, 12

Page 82: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

enum class future_status { ready, timeout, deferred };

template <class R> struct shared_future { future() noexcept; bool valid() const noexcept;

R get();

void wait() const; future_status wait_for( duration ) const; future_status wait_until( time_point ) const;

shared_future(future<R>&& f) noexcept;};

std::shared_future

25

copyable

Tuesday, May 15, 12

Page 83: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

enum class future_status { ready, timeout, deferred };

template <class R> struct shared_future { future() noexcept; bool valid() const noexcept;

R get();

void wait() const; future_status wait_for( duration ) const; future_status wait_until( time_point ) const;

shared_future(future<R>&& f) noexcept;};

std::shared_future

25

copyable

Tuesday, May 15, 12

Page 84: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

enum class future_status { ready, timeout, deferred };

template <class R> struct shared_future { future() noexcept; bool valid() const noexcept;

R get();

void wait() const; future_status wait_for( duration ) const; future_status wait_until( time_point ) const;

shared_future(future<R>&& f) noexcept;};

std::shared_future

25

copyable

basic thread safety: distinct copies can be used concurrently

Tuesday, May 15, 12

Page 85: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

enum class future_status { ready, timeout, deferred };

template <class R> struct shared_future { future() noexcept; bool valid() const noexcept;

R get();

void wait() const; future_status wait_for( duration ) const; future_status wait_until( time_point ) const;

shared_future(future<R>&& f) noexcept;};

std::shared_future

25

multi-shot: afterwards, valid() == true

copyable

Tuesday, May 15, 12

Page 86: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

enum class future_status { ready, timeout, deferred };

template <class R> struct shared_future { future() noexcept; bool valid() const noexcept;

R get();

void wait() const; future_status wait_for( duration ) const; future_status wait_until( time_point ) const;

shared_future(future<R>&& f) noexcept;};

std::shared_future

25

upgrade f to multi-shot, copyable

copyable

Tuesday, May 15, 12

Page 87: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

enum class future_status { ready, timeout, deferred };

template <class R> struct shared_future { future() noexcept; bool valid() const noexcept;

R get();

void wait() const; future_status wait_for( duration ) const; future_status wait_until( time_point ) const;

shared_future(future<R>&& f) noexcept;};

std::shared_future

25

copyable

Tuesday, May 15, 12

Page 88: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

int main(){ std::promise<std::string> audience_send;

auto greet = std::async( [](std::future<std::string> audience_rcv) { std::cout << french["hello"] << ","; std::cout << audience_rcv.get() << std::endl; }, audience_send.get_future() ); audience_send.set_value(french["world"]); greet.wait();}

Pushy, Pushy!

26

Tuesday, May 15, 12

Page 89: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

int main(){ std::promise<std::string> audience_send;

auto greet = std::async( [](std::future<std::string> audience_rcv) { std::cout << french["hello"] << ","; std::cout << audience_rcv.get() << std::endl; }, audience_send.get_future() ); audience_send.set_value(french["world"]); greet.wait();}

Pushy, Pushy!

26

“push” interface

Tuesday, May 15, 12

Page 90: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

int main(){ std::promise<std::string> audience_send;

auto greet = std::async( [](std::future<std::string> audience_rcv) { std::cout << french["hello"] << ","; std::cout << audience_rcv.get() << std::endl; }, audience_send.get_future() ); audience_send.set_value(french["world"]); greet.wait();}

Pushy, Pushy!

26

“pull” interface

Tuesday, May 15, 12

Page 91: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

int main(){ std::promise<std::string> audience_send;

auto greet = std::async( [](std::future<std::string> audience_rcv) { std::cout << french["hello"] << ","; std::cout << audience_rcv.get() << std::endl; }, audience_send.get_future() ); audience_send.set_value(french["world"]); greet.wait();}

Pushy, Pushy!

26

“pull” interface

pull it

Tuesday, May 15, 12

Page 92: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

int main(){ std::promise<std::string> audience_send;

auto greet = std::async( [](std::future<std::string> audience_rcv) { std::cout << french["hello"] << ","; std::cout << audience_rcv.get() << std::endl; }, audience_send.get_future() ); audience_send.set_value(french["world"]); greet.wait();}

Pushy, Pushy!

26

“pull” interface

Tuesday, May 15, 12

Page 93: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

int main(){ std::promise<std::string> audience_send;

auto greet = std::async( [](std::future<std::string> audience_rcv) { std::cout << french["hello"] << ","; std::cout << audience_rcv.get() << std::endl; }, audience_send.get_future() ); audience_send.set_value(french["world"]); greet.wait();}

Pushy, Pushy!

26

“pull” interface

passing the “pull” interface

Tuesday, May 15, 12

Page 94: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

int main(){ std::promise<std::string> audience_send;

auto greet = std::async( [](std::future<std::string> audience_rcv) { std::cout << french["hello"] << ","; std::cout << audience_rcv.get() << std::endl; }, audience_send.get_future() ); audience_send.set_value(french["world"]); greet.wait();}

Pushy, Pushy!

26

push it

Tuesday, May 15, 12

Page 95: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

int main(){ std::promise<std::string> audience_send;

auto greet = std::async( [](std::future<std::string> audience_rcv) { std::cout << french["hello"] << ","; std::cout << audience_rcv.get() << std::endl; }, audience_send.get_future() ); audience_send.set_value(french["world"]); greet.wait();}

Pushy, Pushy!

26

Tuesday, May 15, 12

Page 96: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <class R>struct promise { promise(); template <class Allocator> promise(allocator_arg_t, const Allocator& a);

future<R> get_future();

void set_value(R); void set_exception(exception_ptr p);

void set_value_at_thread_exit(R); void set_exception_at_thread_exit(exception_ptr p);};

std::promise

27

move-only

Tuesday, May 15, 12

Page 97: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <class R>struct promise { promise(); template <class Allocator> promise(allocator_arg_t, const Allocator& a);

future<R> get_future();

void set_value(R); void set_exception(exception_ptr p);

void set_value_at_thread_exit(R); void set_exception_at_thread_exit(exception_ptr p);};

std::promise

27

move-onlyallocate “shared state” for result storage

Tuesday, May 15, 12

Page 98: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <class R>struct promise { promise(); template <class Allocator> promise(allocator_arg_t, const Allocator& a);

future<R> get_future();

void set_value(R); void set_exception(exception_ptr p);

void set_value_at_thread_exit(R); void set_exception_at_thread_exit(exception_ptr p);};

std::promise

27

one-shot: get the “pull” interface

move-only

Tuesday, May 15, 12

Page 99: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <class R>struct promise { promise(); template <class Allocator> promise(allocator_arg_t, const Allocator& a);

future<R> get_future();

void set_value(R); void set_exception(exception_ptr p);

void set_value_at_thread_exit(R); void set_exception_at_thread_exit(exception_ptr p);};

std::promise

27

push result (or exception) and make the future “ready”

move-only

Tuesday, May 15, 12

Page 100: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <class R>struct promise { promise(); template <class Allocator> promise(allocator_arg_t, const Allocator& a);

future<R> get_future();

void set_value(R); void set_exception(exception_ptr p);

void set_value_at_thread_exit(R); void set_exception_at_thread_exit(exception_ptr p);};

std::promise

27

push result but defer readiness

move-only

Tuesday, May 15, 12

Page 101: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <class R>struct promise { promise(); template <class Allocator> promise(allocator_arg_t, const Allocator& a);

future<R> get_future();

void set_value(R); void set_exception(exception_ptr p);

void set_value_at_thread_exit(R); void set_exception_at_thread_exit(exception_ptr p);};

std::promise

27

move-only

Tuesday, May 15, 12

Page 102: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

std::exception_ptr

28

• Is-a NullablePointer (a value type constructible from nullptr)

• Get (a copy of) currently-handled exceptionexception_ptr current_exception() noexcept;

• Throw the exception stored in p[[noreturn]] void rethrow_exception(exception_ptr p);

• Create an exception_ptr to a copy of etemplate <class E>exception_ptr make_exception_ptr(E e) noexcept;

Tuesday, May 15, 12

Page 103: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){

auto greet = std::async([]{ return french["hello"]; });

std::string audience = french["world"]; std::cout << greet.get() << ", " << audience << std::endl;}

Deferring Launch

29

Tuesday, May 15, 12

Page 104: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){

auto greet = std::async([]{ return french["hello"]; });

std::string audience = french["world"]; std::cout << greet.get() << ", " << audience << std::endl;}

Deferring Launch

29

launches the lookup immediately

Tuesday, May 15, 12

Page 105: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){

auto greet = std::async([]{ return french["hello"]; });

std::string audience = french["world"]; std::cout << greet.get() << ", " << audience << std::endl;}

Deferring Launch

29

Tuesday, May 15, 12

Page 106: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){ std::packaged_task<std::string()> do_lookup( []{ return french["hello"]; }); auto greet = do_lookup.get_future(); do_lookup();

std::string audience = french["world"]; std::cout << greet.get() << ", " << audience << std::endl;}

Deferring Launch

30

Tuesday, May 15, 12

Page 107: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){ std::packaged_task<std::string()> do_lookup( []{ return french["hello"]; }); auto greet = do_lookup.get_future(); do_lookup();

std::string audience = french["world"]; std::cout << greet.get() << ", " << audience << std::endl;}

Deferring Launch

30

launch deferred

Tuesday, May 15, 12

Page 108: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){ std::packaged_task<std::string()> do_lookup( []{ return french["hello"]; }); auto greet = do_lookup.get_future(); do_lookup();

std::string audience = french["world"]; std::cout << greet.get() << ", " << audience << std::endl;}

get future result

Deferring Launch

30

Tuesday, May 15, 12

Page 109: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){ std::packaged_task<std::string()> do_lookup( []{ return french["hello"]; }); auto greet = do_lookup.get_future(); do_lookup();

std::string audience = french["world"]; std::cout << greet.get() << ", " << audience << std::endl;}

synchronous launch

Deferring Launch

30

Tuesday, May 15, 12

Page 110: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

asynchronous launch

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){ std::packaged_task<std::string()> do_lookup( []{ return french["hello"]; }); auto greet = do_lookup.get_future(); task_queue.push(std::move(do_lookup));

std::string audience = french["world"]; std::cout << greet.get() << ", " << audience << std::endl;}

Deferring Launch

31

Tuesday, May 15, 12

Page 111: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

std::map<std::string, std::string> french {{"hello","bonjour"}, {"world", "tout le monde"}};

int main(){ std::packaged_task<std::string()> do_lookup( []{ return french["hello"]; }); auto greet = do_lookup.get_future(); task_queue.push(std::move(do_lookup));

std::string audience = french["world"]; std::cout << greet.get() << ", " << audience << std::endl;}

Deferring Launch

31

Tuesday, May 15, 12

Page 112: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template<class> class packaged_task; // undefined

template<class R, class... ArgTypes>struct packaged_task<R(ArgTypes...)> { packaged_task() noexcept; template <class F> explicit packaged_task(F&& f); template <class F, class Alloc> explicit packaged_task(allocator_arg_t, const Alloc& a, F&& f);

future<R> get_future(); bool valid() const noexcept;

void operator()(ArgTypes... ); void make_ready_at_thread_exit(ArgTypes...); void reset();};

std::packaged_task

move-only

Tuesday, May 15, 12

Page 113: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template<class> class packaged_task; // undefined

template<class R, class... ArgTypes>struct packaged_task<R(ArgTypes...)> { packaged_task() noexcept; template <class F> explicit packaged_task(F&& f); template <class F, class Alloc> explicit packaged_task(allocator_arg_t, const Alloc& a, F&& f);

future<R> get_future(); bool valid() const noexcept;

void operator()(ArgTypes... ); void make_ready_at_thread_exit(ArgTypes...); void reset();};

std::packaged_task

move-onlystore f and allocate

“shared state” for result

Tuesday, May 15, 12

Page 114: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template<class> class packaged_task; // undefined

template<class R, class... ArgTypes>struct packaged_task<R(ArgTypes...)> { packaged_task() noexcept; template <class F> explicit packaged_task(F&& f); template <class F, class Alloc> explicit packaged_task(allocator_arg_t, const Alloc& a, F&& f);

future<R> get_future(); bool valid() const noexcept;

void operator()(ArgTypes... ); void make_ready_at_thread_exit(ArgTypes...); void reset();};

std::packaged_task

get the “pull” interface

move-only

Tuesday, May 15, 12

Page 115: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template<class> class packaged_task; // undefined

template<class R, class... ArgTypes>struct packaged_task<R(ArgTypes...)> { packaged_task() noexcept; template <class F> explicit packaged_task(F&& f); template <class F, class Alloc> explicit packaged_task(allocator_arg_t, const Alloc& a, F&& f);

future<R> get_future(); bool valid() const noexcept;

void operator()(ArgTypes... ); void make_ready_at_thread_exit(ArgTypes...); void reset();};

std::packaged_task

move-only

has a shared state?

Tuesday, May 15, 12

Page 116: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template<class> class packaged_task; // undefined

template<class R, class... ArgTypes>struct packaged_task<R(ArgTypes...)> { packaged_task() noexcept; template <class F> explicit packaged_task(F&& f); template <class F, class Alloc> explicit packaged_task(allocator_arg_t, const Alloc& a, F&& f);

future<R> get_future(); bool valid() const noexcept;

void operator()(ArgTypes... ); void make_ready_at_thread_exit(ArgTypes...); void reset();};

std::packaged_task

move-only

invoke f, make future “ready” w/result

Tuesday, May 15, 12

Page 117: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template<class> class packaged_task; // undefined

template<class R, class... ArgTypes>struct packaged_task<R(ArgTypes...)> { packaged_task() noexcept; template <class F> explicit packaged_task(F&& f); template <class F, class Alloc> explicit packaged_task(allocator_arg_t, const Alloc& a, F&& f);

future<R> get_future(); bool valid() const noexcept;

void operator()(ArgTypes... ); void make_ready_at_thread_exit(ArgTypes...); void reset();};

std::packaged_task

move-only

invoke f but defer readiness

Tuesday, May 15, 12

Page 118: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template<class> class packaged_task; // undefined

template<class R, class... ArgTypes>struct packaged_task<R(ArgTypes...)> { packaged_task() noexcept; template <class F> explicit packaged_task(F&& f); template <class F, class Alloc> explicit packaged_task(allocator_arg_t, const Alloc& a, F&& f);

future<R> get_future(); bool valid() const noexcept;

void operator()(ArgTypes... ); void make_ready_at_thread_exit(ArgTypes...); void reset();};

std::packaged_task

move-only

allocate new shared state so we can get_future()/call againTuesday, May 15, 12

Page 119: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template<class> class packaged_task; // undefined

template<class R, class... ArgTypes>struct packaged_task<R(ArgTypes...)> { packaged_task() noexcept; template <class F> explicit packaged_task(F&& f); template <class F, class Alloc> explicit packaged_task(allocator_arg_t, const Alloc& a, F&& f);

future<R> get_future(); bool valid() const noexcept;

void operator()(ArgTypes... ); void make_ready_at_thread_exit(ArgTypes...); void reset();};

std::packaged_task

move-only

Tuesday, May 15, 12

Page 120: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

Lock-Based Data Sharing

33

Tuesday, May 15, 12

Page 121: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

Shared Mutable State

• So far all our examples have been

• functional (“compute this and get back to me with the result”) or

• operating on iostreams, which are already threadsafe

• Avoiding shared, mutable data makes concurrency much simpler!

• However, only “embarrassingly parallel” problems can really be solved that way

34

Tuesday, May 15, 12

Page 122: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

The Challenge of Data Races

• Every piece of data has an invariant that is broken while it is being written

• Threads must not observe these broken invariants

35

Tuesday, May 15, 12

Page 123: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

Concurrent Reads

36

t4 t3

t2t5

t1

xR

RR

R

R

Tuesday, May 15, 12

Page 124: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

Concurrent Reads

36

t4 t3

t2t5

t1

xR

RR

R

R

OK: data doesn't change, so no (temporarily) broken

invariants can be observed.

Tuesday, May 15, 12

Page 125: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

Concurrent Read/Write

37

t4 t3

t2t5

t1

xR

RR

R

W

Tuesday, May 15, 12

Page 126: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

Concurrent Read/Write

37

t4 t3

t2t5

t1

xR

RR

R

W

Data race: readers will observe broken invariants

during the write

Tuesday, May 15, 12

Page 127: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

Single Write

38

t4 t3

t2t5

t1

xW

Tuesday, May 15, 12

Page 128: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

Single Write

38

t4 t3

t2t5

t1

xW

OK: no thread looks, so none observes x's

(temporarily) broken invariant

Tuesday, May 15, 12

Page 129: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

Concurrent Writes

39

t4 t3

t2t5

t1

xW

W

Tuesday, May 15, 12

Page 130: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

Concurrent Writes

39

t4 t3

t2t5

t1

xW

W

Data race: one thread may begin modifying a partially-

changed x and break invariants permanently

Tuesday, May 15, 12

Page 131: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

Thread Safety• Basic thread-safety (“as threadsafe as int”)

• an object can be read concurrently by any number of threads

• distinct copies of an object can be read and written at will in distinct threads (no sharing)

• This is the minimum required for sanity

• Strong thread-safety

• A single object can be read and written at will by any number of threads

• Shared mutable objects must be strongly threadsafe

40

Tuesday, May 15, 12

Page 132: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

Basic Locking

41

• Associate a lock with some shared state x

• A lock can be owned by zero or one threads at any time

• By agreement, every thread

• waits (if necessary) to acquire sole ownership of the lock before reading or writing x, and

• releases ownership of the lock afterward

• x is no longer accessed concurrently; accesses to x are said to be serialized

Tuesday, May 15, 12

Page 133: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

• BasicLockable<L> requiresm.lock() // where m is of type Lm.unlock()

• Lockable<L> requires BasicLockable<L> andbool x = m.try_lock();

• TimedLockable<L> requires Lockable<L> andbool y = m.try_lock_for( duration );bool z = m.try_lock_until( time_point );

Locking Concepts

42

Tuesday, May 15, 12

Page 134: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

• BasicLockable<L> requiresm.lock() // where m is of type Lm.unlock()

• Lockable<L> requires BasicLockable<L> andbool x = m.try_lock();

• TimedLockable<L> requires Lockable<L> andbool y = m.try_lock_for( duration );bool z = m.try_lock_until( time_point );

this_thread acquires m, waiting if necessary

Locking Concepts

42

Tuesday, May 15, 12

Page 135: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

• BasicLockable<L> requiresm.lock() // where m is of type Lm.unlock()

• Lockable<L> requires BasicLockable<L> andbool x = m.try_lock();

• TimedLockable<L> requires Lockable<L> andbool y = m.try_lock_for( duration );bool z = m.try_lock_until( time_point );

this_thread releases m

Locking Concepts

42

Tuesday, May 15, 12

Page 136: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

• BasicLockable<L> requiresm.lock() // where m is of type Lm.unlock()

• Lockable<L> requires BasicLockable<L> andbool x = m.try_lock();

• TimedLockable<L> requires Lockable<L> andbool y = m.try_lock_for( duration );bool z = m.try_lock_until( time_point );

If m is unowned, acquire it and return true, else return false

Locking Concepts

42

Tuesday, May 15, 12

Page 137: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

• BasicLockable<L> requiresm.lock() // where m is of type Lm.unlock()

• Lockable<L> requires BasicLockable<L> andbool x = m.try_lock();

• TimedLockable<L> requires Lockable<L> andbool y = m.try_lock_for( duration );bool z = m.try_lock_until( time_point );

If m can be acquired in time, do so and return true, else return false

Locking Concepts

42

Tuesday, May 15, 12

Page 138: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

• BasicLockable<L> requiresm.lock() // where m is of type Lm.unlock()

• Lockable<L> requires BasicLockable<L> andbool x = m.try_lock();

• TimedLockable<L> requires Lockable<L> andbool y = m.try_lock_for( duration );bool z = m.try_lock_until( time_point );

Locking Concepts

42

Tuesday, May 15, 12

Page 139: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

struct mutex { non-copyable, non-movable constexpr mutex() noexcept;

void lock(); bool try_lock(); void unlock();

typedef unspeci!ed native_handle_type; native_handle_type native_handle();};

std::mutex

43

Tuesday, May 15, 12

Page 140: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

struct mutex { non-copyable, non-movable constexpr mutex() noexcept;

void lock(); bool try_lock(); void unlock();

typedef unspeci!ed native_handle_type; native_handle_type native_handle();};

std::mutex

43

A minimal model of Lockable<L>

Tuesday, May 15, 12

Page 141: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

struct mutex { non-copyable, non-movable constexpr mutex() noexcept;

void lock(); bool try_lock(); void unlock();

typedef unspeci!ed native_handle_type; native_handle_type native_handle();};

std::mutex

43

Tuesday, May 15, 12

Page 142: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <class T>struct shared_stack {

bool empty() const;

T top() const;

void pop();

void push(T x); private: mutable std::mutex m; std::vector<T> v;};

Strongly-Threadsafe Stack

44

Tuesday, May 15, 12

Page 143: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

Associate a mutex with the shared mutable state

template <class T>struct shared_stack {

bool empty() const;

T top() const;

void pop();

void push(T x); private: mutable std::mutex m; std::vector<T> v;};

Strongly-Threadsafe Stack

44

Tuesday, May 15, 12

Page 144: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <class T>struct shared_stack {

bool empty() const;

T top() const;

void pop();

void push(T x); private: mutable std::mutex m; std::vector<T> v;};

Strongly-Threadsafe Stack

44

Tuesday, May 15, 12

Page 145: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <class T>struct shared_stack { bool empty() const { m.lock(); bool r = v.empty(); m.unlock(); return r; }

T top() const; void pop(); void push(T x); private: mutable std::mutex m; std::vector<T> v;};

Strongly-Threadsafe Stack

45

Tuesday, May 15, 12

Page 146: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <class T>struct shared_stack { bool empty() const;

T top() const { m.lock(); T r = v.back(); m.unlock(); return r; } void pop(); void push(T x); private: mutable std::mutex m; std::vector<T> v;};

Strongly-Threadsafe Stack

46

Tuesday, May 15, 12

Page 147: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <class T>struct shared_stack { bool empty() const;

T top() const { m.lock(); T r = v.back(); m.unlock(); return r; } void pop(); void push(T x); private: mutable std::mutex m; std::vector<T> v;};

Strongly-Threadsafe Stack

46

return by value

Tuesday, May 15, 12

Page 148: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <class T>struct shared_stack { bool empty() const;

T top() const { m.lock(); T r = v.back(); m.unlock(); return r; } void pop(); void push(T x); private: mutable std::mutex m; std::vector<T> v;};

Strongly-Threadsafe Stack

46

Tuesday, May 15, 12

Page 149: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <class T>struct shared_stack { bool empty() const;

T top() const { m.lock(); T r = v.back(); m.unlock(); return r; } void pop(); void push(T x); private: mutable std::mutex m; std::vector<T> v;};

Strongly-Threadsafe Stack

46

Q: what if this throws?

Tuesday, May 15, 12

Page 150: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <class T>struct shared_stack { bool empty() const;

T top() const { m.lock(); T r = v.back(); m.unlock(); return r; } void pop(); void push(T x); private: mutable std::mutex m; std::vector<T> v;};

Strongly-Threadsafe Stack

46

Tuesday, May 15, 12

Page 151: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <class T>struct shared_stack { bool empty() const;

T top() const { m.lock(); T r = v.back(); m.unlock(); return r; } void pop(); void push(T x); private: mutable std::mutex m; std::vector<T> v;};

Strongly-Threadsafe Stack

46

A: m remains locked(!)

Tuesday, May 15, 12

Page 152: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <class T>struct shared_stack { bool empty() const;

T top() const { m.lock(); T r = v.back(); m.unlock(); return r; } void pop(); void push(T x); private: mutable std::mutex m; std::vector<T> v;};

Strongly-Threadsafe Stack

46

Tuesday, May 15, 12

Page 153: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <class T>struct shared_stack { bool empty() const;

T top() const { std::lock_guard<std::mutex> lk(m); return v.back(); } void pop(); void push(T x); private: mutable std::mutex m; std::vector<T> v;};

std::lock_guard

47

Tuesday, May 15, 12

Page 154: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <class T>struct shared_stack { bool empty() const;

T top() const { std::lock_guard<std::mutex> lk(m); return v.back(); } void pop(); void push(T x); private: mutable std::mutex m; std::vector<T> v;};

std::lock_guard

47

constructor locks m

Tuesday, May 15, 12

Page 155: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <class T>struct shared_stack { bool empty() const;

T top() const { std::lock_guard<std::mutex> lk(m); return v.back(); } void pop(); void push(T x); private: mutable std::mutex m; std::vector<T> v;};

std::lock_guard

47

destructor unlocks it

Tuesday, May 15, 12

Page 156: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <class T>struct shared_stack { bool empty() const;

T top() const { std::lock_guard<std::mutex> lk(m); return v.back(); } void pop(); void push(T x); private: mutable std::mutex m; std::vector<T> v;};

std::lock_guard

47

Yes, you can lock a mutex directly, but that doesn't

mean you should

Tuesday, May 15, 12

Page 157: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <class T>struct shared_stack { bool empty() const; T top() const;

void pop() { std::lock_guard<std::mutex> lk(m); v.pop_back(); } void push(T x); private: mutable std::mutex m; std::vector<T> v;};

std::lock_guard

48

Tuesday, May 15, 12

Page 158: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <class T>struct shared_stack { bool empty() const; T top() const; void pop();

void push(T x) { std::lock_guard<mutex> lk(m); v.push( std::move(x) ); } private: mutable std::mutex m; std::vector<T> v;};

std::lock_guard

49

Tuesday, May 15, 12

Page 159: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <class Mutex>struct lock_guard { non-copyable, non-movable typedef Mutex mutex_type;

explicit lock_guard(mutex_type& m); lock_guard(mutex_type& m, adopt_lock_t); ~lock_guard();

private: mutex_type& pm;};

std::lock_guard

50

Tuesday, May 15, 12

Page 160: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <class Mutex>struct lock_guard { non-copyable, non-movable typedef Mutex mutex_type;

explicit lock_guard(mutex_type& m); lock_guard(mutex_type& m, adopt_lock_t); ~lock_guard();

private: mutex_type& pm;};

std::lock_guard

50

take ownership of a pre-locked mutex.

Note that there’s no ownership release

Tuesday, May 15, 12

Page 161: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

std::kitchen_sink_locktemplate <class Mutex>struct unique_lock { move-only typedef Mutex mutex_type;

explicit unique_lock(mutex_type& m); unique_lock(mutex_type& m, adopt_lock_t); ~unique_lock();

void lock(); void unlock(); unique_lock() noexcept; unique_lock( mutex_type& m, defer_lock_t) noexcept;

unique_lock( mutex_type& m, try_to_lock_t); bool try_lock();

unique_lock(mutex_type& m, time_point ); bool try_lock_until( time_point );

unique_lock(mutex_type& m, duration ); bool try_lock_for( duration ); mutex_type* mutex() const noexcept; mutex_type *release() noexcept;

bool owns_lock() const noexcept; explicit operator bool () const noexcept;

private: mutex_type *pm; bool owns;};

51

Tuesday, May 15, 12

Page 162: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

std::kitchen_sink_lockstd::unique_locktemplate <class Mutex>struct unique_lock { move-only typedef Mutex mutex_type;

explicit unique_lock(mutex_type& m); unique_lock(mutex_type& m, adopt_lock_t); ~unique_lock();

void lock(); void unlock(); unique_lock() noexcept; unique_lock( mutex_type& m, defer_lock_t) noexcept;

unique_lock( mutex_type& m, try_to_lock_t); bool try_lock();

unique_lock(mutex_type& m, time_point ); bool try_lock_until( time_point );

unique_lock(mutex_type& m, duration ); bool try_lock_for( duration ); mutex_type* mutex() const noexcept; mutex_type *release() noexcept;

bool owns_lock() const noexcept; explicit operator bool () const noexcept;

private: mutex_type *pm; bool owns;};

51

Tuesday, May 15, 12

Page 163: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

std::kitchen_sink_lockstd::unique_locktemplate <class Mutex>struct unique_lock { move-only typedef Mutex mutex_type;

explicit unique_lock(mutex_type& m); unique_lock(mutex_type& m, adopt_lock_t); ~unique_lock();

void lock(); void unlock(); unique_lock() noexcept; unique_lock( mutex_type& m, defer_lock_t) noexcept;

unique_lock( mutex_type& m, try_to_lock_t); bool try_lock();

unique_lock(mutex_type& m, time_point ); bool try_lock_until( time_point );

unique_lock(mutex_type& m, duration ); bool try_lock_for( duration ); mutex_type* mutex() const noexcept; mutex_type *release() noexcept;

bool owns_lock() const noexcept; explicit operator bool () const noexcept;

private: mutex_type *pm; bool owns;};

51

familiar from lock_guard

Tuesday, May 15, 12

Page 164: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

std::kitchen_sink_lockstd::unique_locktemplate <class Mutex>struct unique_lock { move-only typedef Mutex mutex_type;

explicit unique_lock(mutex_type& m); unique_lock(mutex_type& m, adopt_lock_t); ~unique_lock();

void lock(); void unlock(); unique_lock() noexcept; unique_lock( mutex_type& m, defer_lock_t) noexcept;

unique_lock( mutex_type& m, try_to_lock_t); bool try_lock();

unique_lock(mutex_type& m, time_point ); bool try_lock_until( time_point );

unique_lock(mutex_type& m, duration ); bool try_lock_for( duration ); mutex_type* mutex() const noexcept; mutex_type *release() noexcept;

bool owns_lock() const noexcept; explicit operator bool () const noexcept;

private: mutex_type *pm; bool owns;};

51

post-hoc lock/unlock

Tuesday, May 15, 12

Page 165: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

std::kitchen_sink_lockstd::unique_locktemplate <class Mutex>struct unique_lock { move-only typedef Mutex mutex_type;

explicit unique_lock(mutex_type& m); unique_lock(mutex_type& m, adopt_lock_t); ~unique_lock();

void lock(); void unlock(); unique_lock() noexcept; unique_lock( mutex_type& m, defer_lock_t) noexcept;

unique_lock( mutex_type& m, try_to_lock_t); bool try_lock();

unique_lock(mutex_type& m, time_point ); bool try_lock_until( time_point );

unique_lock(mutex_type& m, duration ); bool try_lock_for( duration ); mutex_type* mutex() const noexcept; mutex_type *release() noexcept;

bool owns_lock() const noexcept; explicit operator bool () const noexcept;

private: mutex_type *pm; bool owns;};

51

Tuesday, May 15, 12

Page 166: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <class Mutex>struct unique_lock { move-only typedef Mutex mutex_type;

explicit unique_lock(mutex_type& m); unique_lock(mutex_type& m, adopt_lock_t); ~unique_lock();

void lock(); void unlock(); unique_lock() noexcept; unique_lock( mutex_type& m, defer_lock_t) noexcept;

unique_lock( mutex_type& m, try_to_lock_t); bool try_lock();

unique_lock(mutex_type& m, time_point ); bool try_lock_until( time_point );

unique_lock(mutex_type& m, duration ); bool try_lock_for( duration ); mutex_type* mutex() const noexcept; mutex_type *release() noexcept;

bool owns_lock() const noexcept; explicit operator bool() const noexcept;

private: mutex_type *pm; bool owns;};

std::unique_lock

52

Tuesday, May 15, 12

Page 167: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <class Mutex>struct unique_lock { move-only typedef Mutex mutex_type;

explicit unique_lock(mutex_type& m); unique_lock(mutex_type& m, adopt_lock_t); ~unique_lock();

void lock(); void unlock(); unique_lock() noexcept; unique_lock( mutex_type& m, defer_lock_t) noexcept;

unique_lock( mutex_type& m, try_to_lock_t); bool try_lock();

unique_lock(mutex_type& m, time_point ); bool try_lock_until( time_point );

unique_lock(mutex_type& m, duration ); bool try_lock_for( duration ); mutex_type* mutex() const noexcept; mutex_type *release() noexcept;

bool owns_lock() const noexcept; explicit operator bool() const noexcept;

private: mutex_type *pm; bool owns;};

std::unique_lock

52

construction without ownership

Tuesday, May 15, 12

Page 168: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <class Mutex>struct unique_lock { move-only typedef Mutex mutex_type;

explicit unique_lock(mutex_type& m); unique_lock(mutex_type& m, adopt_lock_t); ~unique_lock();

void lock(); void unlock(); unique_lock() noexcept; unique_lock( mutex_type& m, defer_lock_t) noexcept;

unique_lock( mutex_type& m, try_to_lock_t); bool try_lock();

unique_lock(mutex_type& m, time_point ); bool try_lock_until( time_point );

unique_lock(mutex_type& m, duration ); bool try_lock_for( duration ); mutex_type* mutex() const noexcept; mutex_type *release() noexcept;

bool owns_lock() const noexcept; explicit operator bool() const noexcept;

private: mutex_type *pm; bool owns;};

std::unique_lock

52try-locking

Tuesday, May 15, 12

Page 169: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <class Mutex>struct unique_lock { move-only typedef Mutex mutex_type;

explicit unique_lock(mutex_type& m); unique_lock(mutex_type& m, adopt_lock_t); ~unique_lock();

void lock(); void unlock(); unique_lock() noexcept; unique_lock( mutex_type& m, defer_lock_t) noexcept;

unique_lock( mutex_type& m, try_to_lock_t); bool try_lock();

unique_lock(mutex_type& m, time_point ); bool try_lock_until( time_point );

unique_lock(mutex_type& m, duration ); bool try_lock_for( duration ); mutex_type* mutex() const noexcept; mutex_type *release() noexcept;

bool owns_lock() const noexcept; explicit operator bool() const noexcept;

private: mutex_type *pm; bool owns;};

std::unique_lock

52

timed locking

Tuesday, May 15, 12

Page 170: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <class Mutex>struct unique_lock { move-only typedef Mutex mutex_type;

explicit unique_lock(mutex_type& m); unique_lock(mutex_type& m, adopt_lock_t); ~unique_lock();

void lock(); void unlock(); unique_lock() noexcept; unique_lock( mutex_type& m, defer_lock_t) noexcept;

unique_lock( mutex_type& m, try_to_lock_t); bool try_lock();

unique_lock(mutex_type& m, time_point ); bool try_lock_until( time_point );

unique_lock(mutex_type& m, duration ); bool try_lock_for( duration ); mutex_type* mutex() const noexcept; mutex_type *release() noexcept;

bool owns_lock() const noexcept; explicit operator bool() const noexcept;

private: mutex_type *pm; bool owns;};

std::unique_lock

52

misc.

Tuesday, May 15, 12

Page 171: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <class Mutex>struct unique_lock { move-only typedef Mutex mutex_type;

explicit unique_lock(mutex_type& m); unique_lock(mutex_type& m, adopt_lock_t); ~unique_lock();

void lock(); void unlock(); unique_lock() noexcept; unique_lock( mutex_type& m, defer_lock_t) noexcept;

unique_lock( mutex_type& m, try_to_lock_t); bool try_lock();

unique_lock(mutex_type& m, time_point ); bool try_lock_until( time_point );

unique_lock(mutex_type& m, duration ); bool try_lock_for( duration ); mutex_type* mutex() const noexcept; mutex_type *release() noexcept;

bool owns_lock() const noexcept; explicit operator bool() const noexcept;

private: mutex_type *pm; bool owns;};

std::unique_lock

52

Tuesday, May 15, 12

Page 172: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

Message Passing

53

• Goal: use a bounded FIFO queue to pass messages between threads

• How do I avoid burning CPU:

• looking to see if a message arrived?

• looking to see if there's room to queue a new message?

• And how do I avoid sleeping when there’s work to do?

Tuesday, May 15, 12

Page 173: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <unsigned size, class T>struct bounded_msg_queue{ bounded_msg_queue() : begin(0), end(0), buffered(0) {}

void send(T x); T receive(); private: std::mutex broker; unsigned int begin, end, buffered; T buf[size]; std::condition_variable not_full, not_empty;};

Threadsafe Queue

54

Tuesday, May 15, 12

Page 174: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <unsigned size, class T>struct bounded_msg_queue{ bounded_msg_queue() : begin(0), end(0), buffered(0) {}

void send(T x); T receive(); private: std::mutex broker; unsigned int begin, end, buffered; T buf[size]; std::condition_variable not_full, not_empty;};

Threadsafe Queue

54

Tuesday, May 15, 12

Page 175: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <unsigned size, class T>void bounded_msg_queue<size,T>::send( T x ) { { std::unique_lock<std::mutex> lk(broker); while (buffered == size) not_full.wait(lk);

buf[end] = x; end = (end + 1) % size; ++buffered; } not_empty.notify_all();}

Threadsafe Queue

55

Tuesday, May 15, 12

Page 176: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <unsigned size, class T>void bounded_msg_queue<size,T>::send( T x ) { { std::unique_lock<std::mutex> lk(broker); while (buffered == size) not_full.wait(lk);

buf[end] = x; end = (end + 1) % size; ++buffered; } not_empty.notify_all();}

Threadsafe Queue

55

always start locked

Tuesday, May 15, 12

Page 177: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <unsigned size, class T>void bounded_msg_queue<size,T>::send( T x ) { { std::unique_lock<std::mutex> lk(broker); while (buffered == size) not_full.wait(lk);

buf[end] = x; end = (end + 1) % size; ++buffered; } not_empty.notify_all();}

Threadsafe Queue

55

while condition not satisfied

Tuesday, May 15, 12

Page 178: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <unsigned size, class T>void bounded_msg_queue<size,T>::send( T x ) { { std::unique_lock<std::mutex> lk(broker); while (buffered == size) not_full.wait(lk);

buf[end] = x; end = (end + 1) % size; ++buffered; } not_empty.notify_all();}

Threadsafe Queue

55

wait to be notified that something changed

(library unlocks for us)

Tuesday, May 15, 12

Page 179: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <unsigned size, class T>void bounded_msg_queue<size,T>::send( T x ) { { std::unique_lock<std::mutex> lk(broker); while (buffered == size) not_full.wait(lk);

buf[end] = x; end = (end + 1) % size; ++buffered; } not_empty.notify_all();}

Threadsafe Queue

55

we've changed conditions for readers!

Tuesday, May 15, 12

Page 180: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <unsigned size, class T>void bounded_msg_queue<size,T>::send( T x ) { { std::unique_lock<std::mutex> lk(broker); while (buffered == size) not_full.wait(lk);

buf[end] = x; end = (end + 1) % size; ++buffered; } not_empty.notify_all();}

Threadsafe Queue

55

Tuesday, May 15, 12

Page 181: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

template <unsigned size, class T>T bounded_msg_queue<size,T>::receive(){ T r; { std::unique_lock<std::mutex> lk(broker); while (buffered == 0) not_empty.wait(lk);

r = buf[begin]; begin = (begin + 1) % size; --buffered; } not_full.notify_all(); return r;}

Threadsafe Queue

56

Tuesday, May 15, 12

Page 182: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

struct condition_variable { noncopyable, non-movable condition_variable();

typedef unspecified native_handle_type; native_handle_type native_handle(); void notify_one() noexcept; void notify_all() noexcept;

void wait( unique_lock<mutex>& lock);

template <class Predicate> void wait( unique_lock<mutex>& lock, Predicate p);

cv_status wait_until( unique_lock<mutex>& lock, time_point);

template <class Predicate> bool wait_until( unique_lock<mutex>& lock, time_point, Predicate pred); cv_status wait_for( unique_lock<mutex>& lock, duration );

template <class Predicate> bool wait_for( unique_lock<mutex>& lock, duration, Predicate);};

std::condition_variable

57

Tuesday, May 15, 12

Page 183: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

boost::shared_mutex

• Not in the standard library.

See http://boost.org/libs/thread

• Can be acquired by multiple readers or one writer

• Great for often-read, seldom-written data

58

Tuesday, May 15, 12

Page 184: C++11 Concurrency - GitHub · Agenda • High-level components • Low-level lock-based components 2 Tuesday, May 15, 12

Go forth and mutate!(safely)

59

Tuesday, May 15, 12