SlideShare a Scribd company logo
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Better Code: Concurrency
Sean Parent | Principal Scientist
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Better Code
! Regular Type
! Goal: Implement Complete and Efficient Types
! Algorithms
! Goal: No Raw Loops
! Data Structures
! Goal: No Incidental Data Structures
! Runtime Polymorphism
! Goal: No Raw Pointers
! Concurrency
! Goal: No Raw Synchronization Primitives
! …
2
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Common Themes
! Manage Relationships
! Understand the Fundamentals
! Code Simply
3
© 2013 Adobe Systems Incorporated. All Rights Reserved.
Demo
4
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Concurrency
! Concurrency: when tasks start, run, and complete in overlapping time periods
! Parallelism: when two or more tasks execute simultaneously
! Why?
! Enable performance through parallelism
! Improve interactivity by handling user actions concurrent with processing and IO
5
http://docs.oracle.com/cd/E19455-01/806-5257/6je9h032b/index.html
© 2013 Adobe Systems Incorporated. All Rights Reserved.
No Raw Synchronization Primitives
6
© 2013 Adobe Systems Incorporated. All Rights Reserved.
What are raw synchronization primitives?
! Synchronization primitives are basic constructs such as:
! Mutex
! Atomic
! Semaphore
! Memory Fence
! Condition Variable
7
© 2014 Adobe Systems Incorporated. All Rights Reserved. 8
Desktop Compute Power (8-core 3.5GHz Sandy Bridge + AMD Radeon 6950)
8
© 2014 Adobe Systems Incorporated. All Rights Reserved. 8
Desktop Compute Power (8-core 3.5GHz Sandy Bridge + AMD Radeon 6950)
8
0 750 1500 2250 3000
GPU Vectorization Multi-thread Scalar (GFlops)
© 2014 Adobe Systems Incorporated. All Rights Reserved. 8
Desktop Compute Power (8-core 3.5GHz Sandy Bridge + AMD Radeon 6950)
8
OpenGL
OpenCL
CUDA
Direct Compute
C++ AMP
DirectX
0 750 1500 2250 3000
GPU Vectorization Multi-thread Scalar (GFlops)
© 2014 Adobe Systems Incorporated. All Rights Reserved. 8
Desktop Compute Power (8-core 3.5GHz Sandy Bridge + AMD Radeon 6950)
Intrinsics
Auto-vectorization
OpenCL
8
OpenGL
OpenCL
CUDA
Direct Compute
C++ AMP
DirectX
0 750 1500 2250 3000
GPU Vectorization Multi-thread Scalar (GFlops)
© 2014 Adobe Systems Incorporated. All Rights Reserved. 8
Desktop Compute Power (8-core 3.5GHz Sandy Bridge + AMD Radeon 6950)
Intrinsics
Auto-vectorization
OpenCL
8
TBB
GCD
OpenMP
C++11
OpenGL
OpenCL
CUDA
Direct Compute
C++ AMP
DirectX
0 750 1500 2250 3000
GPU Vectorization Multi-thread Scalar (GFlops)
© 2014 Adobe Systems Incorporated. All Rights Reserved. 8
Desktop Compute Power (8-core 3.5GHz Sandy Bridge + AMD Radeon 6950)
Intrinsics
Auto-vectorization
OpenCL
8
Straight C++
TBB
GCD
OpenMP
C++11
OpenGL
OpenCL
CUDA
Direct Compute
C++ AMP
DirectX
0 750 1500 2250 3000
GPU Vectorization Multi-thread Scalar (GFlops)
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Threads and Tasks
! Thread: Execution environment consisting of a stack and processor state running in parallel to other threads
! Task: A unit of work, often a function, to be executed on a thread
! Tasks are scheduled on a thread pool to optimize machine utilization
9
© 2014 Adobe Systems Incorporated. All Rights Reserved.
C++14 and Tasks
! C++14 does not have a task system
! Threads
! Futures (more on this)
10
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Amdahl’s Law
11
http://en.wikipedia.org/wiki/Amdahl%27s_law
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Amdahl’s Law
12
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Processors
Performance
© 2014 Adobe Systems Incorporated. All Rights Reserved.
What Makes It Slow
! Starvation
! Latency
! Overhead
! Wait
13
Hartmut Kaiser - HPX
© 2013 Adobe Systems Incorporated. All Rights Reserved.
Why No Raw Synchronization Primitives?
14
Object
thread
thread
thread
© 2013 Adobe Systems Incorporated. All Rights Reserved.
Why No Raw Synchronization Primitives?
14
Object
thread
thread
thread
STOP
STOP
GO
© 2013 Adobe Systems Incorporated. All Rights Reserved.
Why No Raw Synchronization Primitives?
14
Object
thread
thread
thread
STOP
STOP
GO
© 2013 Adobe Systems Incorporated. All Rights Reserved.
Why No Raw Synchronization Primitives?
14
Object
thread
thread
thread
STOP
STOP
GO
© 2013 Adobe Systems Incorporated. All Rights Reserved.
Minimize Locks
15
STOP
© 2013 Adobe Systems Incorporated. All Rights Reserved.
Minimize Locks
15
STOP
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Building a Task System
! Portable Reference Implementation in C++14
! Windows - Window Thread Pool and PPL
! Apple - Grand Central Dispatch (libdispatch)
! open source, runs on Linux and Android
! Intel TBB - many platforms
! open source
! HPX - many platforms
! open source
16
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Building a Task System
17
http://docs.oracle.com/cd/E19253-01/816-5137/ggedn/index.html
Core Core Core…
Thread Thread Thread
.
.
.
Task
Task
Task
Task
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Building a Task System
18
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Building a Task System
using lock_t = unique_lock<mutex>;
18
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Building a Task System
using lock_t = unique_lock<mutex>;
class notification_queue {
deque<function<void()>> _q;
mutex _mutex;
condition_variable _ready;
18
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Building a Task System
using lock_t = unique_lock<mutex>;
class notification_queue {
deque<function<void()>> _q;
mutex _mutex;
condition_variable _ready;
public:
void pop(function<void()>& x) {
lock_t lock{_mutex};
while (_q.empty()) _ready.wait(lock);
x = move(_q.front());
_q.pop_front();
}
18
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Building a Task System
using lock_t = unique_lock<mutex>;
class notification_queue {
deque<function<void()>> _q;
mutex _mutex;
condition_variable _ready;
public:
void pop(function<void()>& x) {
lock_t lock{_mutex};
while (_q.empty()) _ready.wait(lock);
x = move(_q.front());
_q.pop_front();
}
template<typename F>
void push(F&& f) {
{
lock_t lock{_mutex};
_q.emplace_back(forward<F>(f));
}
_ready.notify_one();
}
};
18
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Building a Task System
19
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Building a Task System
class task_system {
const unsigned _count{thread::hardware_concurrency()};
vector<thread> _threads;
notification_queue _q;
19
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Building a Task System
class task_system {
const unsigned _count{thread::hardware_concurrency()};
vector<thread> _threads;
notification_queue _q;
void run(unsigned i) {
while (true) {
function<void()> f;
_q.pop(f);
f();
}
}
19
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Building a Task System
class task_system {
const unsigned _count{thread::hardware_concurrency()};
vector<thread> _threads;
notification_queue _q;
void run(unsigned i) {
while (true) {
function<void()> f;
_q.pop(f);
f();
}
}
public:
task_system() {
for (unsigned n = 0; n != _count; ++n) {
_threads.emplace_back([&, n]{ run(n); });
}
}
19
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Building a Task System
class task_system {
const unsigned _count{thread::hardware_concurrency()};
vector<thread> _threads;
notification_queue _q;
void run(unsigned i) {
while (true) {
function<void()> f;
_q.pop(f);
f();
}
}
public:
task_system() {
for (unsigned n = 0; n != _count; ++n) {
_threads.emplace_back([&, n]{ run(n); });
}
}
~task_system() {
for (auto& e : _threads) e.join();
}
19
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Building a Task System
class task_system {
const unsigned _count{thread::hardware_concurrency()};
vector<thread> _threads;
notification_queue _q;
void run(unsigned i) {
while (true) {
function<void()> f;
_q.pop(f);
f();
}
}
public:
task_system() {
for (unsigned n = 0; n != _count; ++n) {
_threads.emplace_back([&, n]{ run(n); });
}
}
~task_system() {
for (auto& e : _threads) e.join();
}
template <typename F>
void async_(F&& f) {
_q.push(forward<F>(f));
}
};
19
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Building a Task System
class notification_queue {
deque<function<void()>> _q;
bool _done{false};
mutex _mutex;
condition_variable _ready;
public:
void done() {
{
unique_lock<mutex> lock{_mutex};
_done = true;
}
_ready.notify_all();
}
bool pop(function<void()>& x) {
lock_t lock{_mutex};
while (_q.empty() && !_done) _ready.wait(lock);
if (_q.empty()) return false;
x = move(_q.front());
_q.pop_front();
return true;
}
template<typename F>
void push(F&& f) {
{
lock_t lock{_mutex};
_q.emplace_back(forward<F>(f));
20
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Building a Task System
class notification_queue {
deque<function<void()>> _q;
bool _done{false};
mutex _mutex;
condition_variable _ready;
public:
void done() {
{
unique_lock<mutex> lock{_mutex};
_done = true;
}
_ready.notify_all();
}
bool pop(function<void()>& x) {
lock_t lock{_mutex};
while (_q.empty() && !_done) _ready.wait(lock);
if (_q.empty()) return false;
x = move(_q.front());
_q.pop_front();
return true;
}
template<typename F>
void push(F&& f) {
{
lock_t lock{_mutex};
_q.emplace_back(forward<F>(f));
20
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Building a Task System
class notification_queue {
deque<function<void()>> _q;
bool _done{false};
mutex _mutex;
condition_variable _ready;
public:
void done() {
{
unique_lock<mutex> lock{_mutex};
_done = true;
}
_ready.notify_all();
}
bool pop(function<void()>& x) {
lock_t lock{_mutex};
while (_q.empty() && !_done) _ready.wait(lock);
if (_q.empty()) return false;
x = move(_q.front());
_q.pop_front();
return true;
}
template<typename F>
void push(F&& f) {
{
lock_t lock{_mutex};
_q.emplace_back(forward<F>(f));
20
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Building a Task System
class notification_queue {
deque<function<void()>> _q;
bool _done{false};
mutex _mutex;
condition_variable _ready;
public:
void done() {
{
unique_lock<mutex> lock{_mutex};
_done = true;
}
_ready.notify_all();
}
bool pop(function<void()>& x) {
lock_t lock{_mutex};
while (_q.empty() && !_done) _ready.wait(lock);
if (_q.empty()) return false;
x = move(_q.front());
_q.pop_front();
return true;
}
template<typename F>
void push(F&& f) {
{
lock_t lock{_mutex};
_q.emplace_back(forward<F>(f));
20
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Building a Task System
21
Core Core Core…
Thread Thread Thread
.
.
.
Task
Task
Task
Task
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Building a Task System
21
Core Core Core…
Thread Thread Thread
.
.
.
Task
Task
Task
Task
© 2013 Adobe Systems Incorporated. All Rights Reserved.
Why No Raw Synchronization Primitives?
22
Object
thread
thread
thread
© 2013 Adobe Systems Incorporated. All Rights Reserved.
Why No Raw Synchronization Primitives?
22
Object
thread
thread
thread
STOP
STOP
GO
© 2013 Adobe Systems Incorporated. All Rights Reserved.
Why No Raw Synchronization Primitives?
22
Object
thread
thread
thread
STOP
STOP
GO
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Building a Task System
23
Core Core Core…
Thread Thread Thread
.
.
.
Task
Task
Task
Task
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Building a Task System
23
Core Core Core…
Thread Thread Thread
.
.
.
Task
Task
Task
Task
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Building a Task System
24
Core Core Core…
Thread Thread Thread
.
.
.
Task
Task
Task
.
.
.
Task
Task
Task
.
.
.
Task
Task
Task
Task
Scheduler
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Building a Task System
class task_system {
const unsigned _count{thread::hardware_concurrency()};
vector<thread> _threads;
vector<notification_queue> _q{_count};
atomic<unsigned> _index{0};
void run(unsigned i) {
while (true) {
function<void()> f;
if (!_q[i].pop(f)) break;
f();
}
}
public:
task_system() { }
~task_system() {
for (auto& e : _q) e.done();
for (auto& e : _threads) e.join();
}
template <typename F>
void async_(F&& f) {
auto i = _index++;
_q[i % _count].push(forward<F>(f));
}
};
25
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Building a Task System
class task_system {
const unsigned _count{thread::hardware_concurrency()};
vector<thread> _threads;
vector<notification_queue> _q{_count};
atomic<unsigned> _index{0};
void run(unsigned i) {
while (true) {
function<void()> f;
if (!_q[i].pop(f)) break;
f();
}
}
public:
task_system() { }
~task_system() {
for (auto& e : _q) e.done();
for (auto& e : _threads) e.join();
}
template <typename F>
void async_(F&& f) {
auto i = _index++;
_q[i % _count].push(forward<F>(f));
}
};
25
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Building a Task System
class task_system {
const unsigned _count{thread::hardware_concurrency()};
vector<thread> _threads;
vector<notification_queue> _q{_count};
atomic<unsigned> _index{0};
void run(unsigned i) {
while (true) {
function<void()> f;
if (!_q[i].pop(f)) break;
f();
}
}
public:
task_system() { }
~task_system() {
for (auto& e : _q) e.done();
for (auto& e : _threads) e.join();
}
template <typename F>
void async_(F&& f) {
auto i = _index++;
_q[i % _count].push(forward<F>(f));
}
};
25
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Building a Task System
class task_system {
const unsigned _count{thread::hardware_concurrency()};
vector<thread> _threads;
vector<notification_queue> _q{_count};
atomic<unsigned> _index{0};
void run(unsigned i) {
while (true) {
function<void()> f;
if (!_q[i].pop(f)) break;
f();
}
}
public:
task_system() { }
~task_system() {
for (auto& e : _q) e.done();
for (auto& e : _threads) e.join();
}
template <typename F>
void async_(F&& f) {
auto i = _index++;
_q[i % _count].push(forward<F>(f));
}
};
25
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Building a Task System
class task_system {
const unsigned _count{thread::hardware_concurrency()};
vector<thread> _threads;
vector<notification_queue> _q{_count};
atomic<unsigned> _index{0};
void run(unsigned i) {
while (true) {
function<void()> f;
if (!_q[i].pop(f)) break;
f();
}
}
public:
task_system() { }
~task_system() {
for (auto& e : _q) e.done();
for (auto& e : _threads) e.join();
}
template <typename F>
void async_(F&& f) {
auto i = _index++;
_q[i % _count].push(forward<F>(f));
}
};
25
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Building a Task System
26
Core Core Core…
Thread Thread Thread
.
.
.
Task
Task
Task
.
.
.
Task
Task
Task
.
.
.
Task
Task
Task
Task
Scheduler
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Building a Task System
26
Core Core Core…
Thread Thread Thread
.
.
.
Task
Task
Task
.
.
.
Task
Task
Task
.
.
.
Task
Task
Task
Task
Scheduler
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Building a Task System
27
Core Core Core…
Thread Thread Thread
.
.
.
Task
Task
Task
.
.
.
Task
Task
Task
.
.
.
Task
Task
Task
Task
Scheduler
Task Stealing
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Building a Task System
class notification_queue {
deque<function<void()>> _q;
bool _done{false};
mutex _mutex;
condition_variable _ready;
public:
bool try_pop(function<void()>& x) {
lock_t lock{_mutex, try_to_lock};
if (!lock || _q.empty()) return false;
x = move(_q.front());
_q.pop_front();
return true;
}
template<typename F>
bool try_push(F&& f) {
{
lock_t lock{_mutex, try_to_lock};
if (!lock) return false;
_q.emplace_back(forward<F>(f));
}
_ready.notify_one();
return true;
}
void done() {
{
unique_lock<mutex> lock{_mutex};
28
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Building a Task System
class notification_queue {
deque<function<void()>> _q;
bool _done{false};
mutex _mutex;
condition_variable _ready;
public:
bool try_pop(function<void()>& x) {
lock_t lock{_mutex, try_to_lock};
if (!lock || _q.empty()) return false;
x = move(_q.front());
_q.pop_front();
return true;
}
template<typename F>
bool try_push(F&& f) {
{
lock_t lock{_mutex, try_to_lock};
if (!lock) return false;
_q.emplace_back(forward<F>(f));
}
_ready.notify_one();
return true;
}
void done() {
{
unique_lock<mutex> lock{_mutex};
28
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Building a Task System
class notification_queue {
deque<function<void()>> _q;
bool _done{false};
mutex _mutex;
condition_variable _ready;
public:
bool try_pop(function<void()>& x) {
lock_t lock{_mutex, try_to_lock};
if (!lock || _q.empty()) return false;
x = move(_q.front());
_q.pop_front();
return true;
}
template<typename F>
bool try_push(F&& f) {
{
lock_t lock{_mutex, try_to_lock};
if (!lock) return false;
_q.emplace_back(forward<F>(f));
}
_ready.notify_one();
return true;
}
void done() {
{
unique_lock<mutex> lock{_mutex};
28
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Building a Task System
void run(unsigned i) {
while (true) {
function<void()> f;
for (unsigned n = 0; n != _count; ++n) {
if (_q[(i + n) % _count].try_pop(f)) break;
}
if (!f && !_q[i].pop(f)) break;
f();
}
}
public:
task_system() { }
~task_system() { }
template <typename F>
void async_(F&& f) {
auto i = _index++;
for (unsigned n = 0; n != _count; ++n) {
if (_q[(i + n) % _count].try_push(forward<F>(f))) return;
}
_q[i % _count].push(forward<F>(f));
}
};
29
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Building a Task System
void run(unsigned i) {
while (true) {
function<void()> f;
for (unsigned n = 0; n != _count; ++n) {
if (_q[(i + n) % _count].try_pop(f)) break;
}
if (!f && !_q[i].pop(f)) break;
f();
}
}
public:
task_system() { }
~task_system() { }
template <typename F>
void async_(F&& f) {
auto i = _index++;
for (unsigned n = 0; n != _count; ++n) {
if (_q[(i + n) % _count].try_push(forward<F>(f))) return;
}
_q[i % _count].push(forward<F>(f));
}
};
29
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Building a Task System
void run(unsigned i) {
while (true) {
function<void()> f;
for (unsigned n = 0; n != _count; ++n) {
if (_q[(i + n) % _count].try_pop(f)) break;
}
if (!f && !_q[i].pop(f)) break;
f();
}
}
public:
task_system() { }
~task_system() { }
template <typename F>
void async_(F&& f) {
auto i = _index++;
for (unsigned n = 0; n != _count; ++n) {
if (_q[(i + n) % _count].try_push(forward<F>(f))) return;
}
_q[i % _count].push(forward<F>(f));
}
};
29
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Building a Task System
30
Core Core Core…
Thread Thread Thread
.
.
.
Task
Task
Task
.
.
.
Task
Task
Task
.
.
.
Task
Task
Task
Task
Scheduler
Task Stealing
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Building a Task System
30
Core Core Core…
Thread Thread Thread
.
.
.
Task
Task
Task
.
.
.
Task
Task
Task
.
.
.
Task
Task
Task
Task
Scheduler
Task Stealing
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Task System
! Within a few percentage points of Apple’s GCD (libdispatch) under load
! Can be improved by spinning more on try_pop in run
31
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Futures
32
future<cpp_int> x = async([]{ return fibonacci<cpp_int>(1'000'000); });
// Do Something
cout << x.get() << endl;
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Futures
! Fibonacci is often used as an example for parallel algorithms
! Please stop…
32
future<cpp_int> x = async([]{ return fibonacci<cpp_int>(1'000'000); });
// Do Something
cout << x.get() << endl;
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Public Service Announcement - How to Write Fibonacci
template <typename T, typename N, typename O>
T power(T x, N n, O op)
{
if (n == 0) return identity_element(op);
while ((n & 1) == 0) {
n >>= 1;
x = op(x, x);
}
T result = x;
n >>= 1;
while (n != 0) {
x = op(x, x);
if ((n & 1) != 0) result = op(result, x);
n >>= 1;
}
return result;
}
33
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Public Service Announcement - How to Write Fibonacci
template <typename T, typename N, typename O>
T power(T x, N n, O op)
{
if (n == 0) return identity_element(op);
while ((n & 1) == 0) {
n >>= 1;
x = op(x, x);
}
T result = x;
n >>= 1;
while (n != 0) {
x = op(x, x);
if ((n & 1) != 0) result = op(result, x);
n >>= 1;
}
return result;
}
33
Egyptian Multiplication (Russian Peasant Algorithm)
See “From Mathematics to Generic Programming” - Alex Stepanov and Dan Rose
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Public Service Announcement - How to Write Fibonacci
template <typename N>
struct multiply_2x2 {
array<N, 4> operator()(const array<N, 4>& x, const array<N, 4>& y)
{
return { x[0] * y[0] + x[1] * y[2], x[0] * y[1] + x[1] * y[3],
x[2] * y[0] + x[3] * y[2], x[2] * y[1] + x[3] * y[3] };
}
};
template <typename N>
array<N, 4> identity_element(const multiply_2x2<N>&) { return { N(1), N(0), N(0), N(1) }; }
template <typename R, typename N>
R fibonacci(N n) {
if (n == 0) return R(0);
return power(array<R, 4>{ 1, 1, 1, 0 }, N(n - 1), multiply_2x2<R>())[0];
}
34
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Futures
19532821287077577316320149475962563324435429965918733969534051945716252578870156947666419876341501461288795
24335220236084625510912019560233744015438115196636156919962125642894303370113827800638002767411527927466669
86557837931882283206127149758323033485489348957259923072291290192820926433162752173086146001791258204269965
99360209593392020051848620284024473431398113674187202038684801753185386211128781082406177413832935545616876
06454065125954718029126547942894036981659206361019359291352135410376799082940320155702716115395031975973247
78216295763162965335669477766328506234524559346064757502593581344345781676764625878859011372729907372947851
14480895724561915035070255895291168685500088020132334587472177947814475467920160901706425856293597475465327
57575740077432034913428785189795354304734560307765078938767286539166799232817449361991523768149557632085371
04785970618843873153058239562756087906310781900497516959470973671389174570455520213512335079440336071203050
41446852210415650373210679322756258647511914611417360349681217380234224786080292021093192496490409832397066
83247054441763512526732455275419501683845206023007394959854279298297831204382115757645787692495583351402522
15272066244180900325938075362849179668095297118507191379833678873770459913639333955814212036990261617972113
25091840023055327607104316478190974300434647793363287601469996128023925829471557316688943339455429292871877
48774789204296166356536610796023919702109728472966709427334586344798048633944635211654971507261342768205479
32093175079888010130416027982506354182344034558742236701282666356934611294613123128389060036547327660245693
15151850018328483150645480029978935985161237074046158229354440701748339514575869547491750264542126364262224
72060048855462589961190475892101224280542898621594646662478564373572217775549876087685912030118551635668902
01034463998397732663888903650784161807091545252992759735213957415477729146008794314339156060445825107823511
66271892637923313014643880597879468444879060576786297460989627426663569682474293386740207436559426057944790
71193052258931590719386545525880429139747140181849169733838138446154843063123649290835584278078456131936457
55911722136946338180311600307896211668652895953778436464402382516362449718197385444149563131714002850338928
22274134603018094224837216321854717270452813824078425638747365249141118080783866506339945376239206700513391
87333107136069698189628284763245423299306272870457991293245741167533902274499963096566680922262516468582544
55785134982414412726124015815753818098466667145006988839178551800894370189025721992485208742915560261917752
28124660628996787166529678487268484905041328497297712688011639978376434280202452251550102240354169885185375
01584673881194047619720619603126534496759917893244478170702904446589571950228809157793897642423751814020998
99958161231477902295781100168670186738619861797138139854666281969548553740707356228616165539428076418408092
12047932816683005984504787929406356318097479755152035094682765918741610907637506902765294367561539803261388
35
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Futures
15790155892833100345673846243104676900000936756893803676769777642059716492347060997973282994459039755683869
10568541105888505197986232161807165960864316652383369579251545877324797429523572491518310013505994095431367
23454418539676396422570487868443336735568511535850565172490141772333018072390350689838662532338266203548476
87722321662223383305226882245421258277211223435986491973881404168406609216954760818955479619408040043497601
35646408461148077885537891122888139618703907906033147416881433658136276942006644505679690480702792206520855
12245086839375655196861305232092138041808273198852928058246964575561801618520046644949262341864859342928965
21378574554544426221453176445385228867960454072522804961741905198550911362542849130027243353553345377968558
49780195976636516290598457219043489821358221206856924121139313137132134865741440892670003665555632446499775
56853514681289887391700907057970839124191923062570547772748610990924519168225326823578140721238189631411471
29610287340041050015549547086272721534936510345705849389706515725684266079756708385889612130516276472992631
59674474594901199950849178952149715987731953191759591623424021718579696778102054496598766846143959650647332
21985323521378108187030642875506951890343587181633604126397675020909133548480151135951824112432636080497447
37395896608759569909256138919905403404664655310556021101996525724843421071082933739200159651403373870955680
75656822683537933983982488022723770319785461480932302347255796621173892988541730741484707211664044157057536
04582256143224299859780683239696543855523783781413866750792868372058020433472254190336846843017198934115689
96526838242546875
35
0.72s to calculate
208,988 digits
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Futures
36
future<cpp_int> x = async([]{ return fibonacci<cpp_int>(1'000'000); });
// Do Something
cout << x.get() << endl;
f(…)->r
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Futures
37
f(…) r
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Futures
37
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Futures
! Futures allow minimal code transformations to express dependencies
38
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Futures: What year is this?
! C++14 futures have:
! Exception Marshaling
! Sever Notification (broken promise)
39
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Futures: What year is this?
! C++14 futures lack:
! Continuations - .then()
! Joins - when_all()
! Cancelation
! Progress Monitoring (Except Ready)
! …
! And C++14 futures don’t compose (easily) to add these features
40
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Futures: Continuations
41
© 2013 Adobe Systems Incorporated. All Rights Reserved.
Futures: Continuations
! Blocking on std::future.get() has two problems
! One thread resource is consumed, increasing contention
! Any subsequent non-dependent calculations on the task are also blocked
! C++14 doesn’t have continuations
! GCD has serialized queues and groups
! PPL has chained tasks
! TBB has flow graphs
! TS Concurrency will have them
! Boost futures have them now
42
© 2013 Adobe Systems Incorporated. All Rights Reserved.
Futures: Continuations
future<cpp_int> x = async([]{ return fibonacci<cpp_int>(1'000'000); });
future<void> y = x.then([](future<cpp_int> x){ cout << x.get() << endl; });
// Do something
y.wait();
43
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Futures
44
© 2013 Adobe Systems Incorporated. All Rights Reserved.
Futures: Continuations
auto x = async([]{ return fibonacci<cpp_int>(1'000'000); });
auto y = async([]{ return fibonacci<cpp_int>(2'000'000); });
auto z = when_all(std::move(x), std::move(y)).then([](auto f){
auto t = f.get();
return cpp_int(get<0>(t).get() * get<1>(t).get());
});
cout << z.get() << endl;
45
© 2013 Adobe Systems Incorporated. All Rights Reserved.
Futures: Continuations
auto x = async([]{ return fibonacci<cpp_int>(1'000'000); });
auto y = async([]{ return fibonacci<cpp_int>(2'000'000); });
auto z = when_all(std::move(x), std::move(y)).then([](auto f){
auto t = f.get();
return cpp_int(get<0>(t).get() * get<1>(t).get());
});
cout << z.get() << endl;
45
f is a future tuple of futures
© 2013 Adobe Systems Incorporated. All Rights Reserved.
Futures: Continuations
auto x = async([]{ return fibonacci<cpp_int>(1'000'000); });
auto y = async([]{ return fibonacci<cpp_int>(2'000'000); });
auto z = when_all(std::move(x), std::move(y)).then([](auto f){
auto t = f.get();
return cpp_int(get<0>(t).get() * get<1>(t).get());
});
cout << z.get() << endl;
45
f is a future tuple of futures
result is 626,964 digits
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Futures
46
© 2013 Adobe Systems Incorporated. All Rights Reserved.
Futures: Continuations
future<cpp_int> x = async([]{ return fibonacci<cpp_int>(100); });
future<cpp_int> y = x.then([](future<cpp_int> x){ return cpp_int(x.get() * 2); });
future<cpp_int> z = x.then([](future<cpp_int> x){ return cpp_int(x.get() / 15); });
47
© 2013 Adobe Systems Incorporated. All Rights Reserved.
Futures: Continuations
future<cpp_int> x = async([]{ return fibonacci<cpp_int>(100); });
future<cpp_int> y = x.then([](future<cpp_int> x){ return cpp_int(x.get() * 2); });
future<cpp_int> z = x.then([](future<cpp_int> x){ return cpp_int(x.get() / 15); });
47
Assertion failed: (px != 0), function operator->, file shared_ptr.hpp, line 648.
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Continuations
! Desired behavior
! A future should behave as a regular type - a token for the actual value
! shared_futures let me pass them around and do multiple get() operations, but don’t fix continuations
! [at least with boost]
! Releasing the last instance of a future should cancel (no-op) any unexecuted, contributing, operations
48
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Futures
49
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Futures
49
shared
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Futures
50
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Futures
50
shared
shared
shared
© 2013 Adobe Systems Incorporated. All Rights Reserved.
Futures: Building, The
template <typename>
struct result_of_; //not defined
template <typename R, typename... Args>
struct result_of_<R(Args...)> { using type = R; };
template <typename F>
using result_of_t_ = typename result_of_<F>::type;
51
© 2013 Adobe Systems Incorporated. All Rights Reserved.
Futures: Building, The
template <typename>
struct result_of_; //not defined
template <typename R, typename... Args>
struct result_of_<R(Args...)> { using type = R; };
template <typename F>
using result_of_t_ = typename result_of_<F>::type;
51
result_of_t_<int(double)> -> int
© 2013 Adobe Systems Incorporated. All Rights Reserved.
Futures: Building, The
template <typename> class packaged_task; //not defined
template <typename R>
class future {
shared_ptr</* ... */> _p;
public:
future() = default;
template <typename F>
auto then(F&& f) { }
const R& get() const { }
};
template<typename R, typename ...Args >
class packaged_task<R (Args...)> {
weak_ptr</* ... */> _p;
public:
packaged_task() = default;
template <typename... A>
void operator()(A&&... args) const { }
};
52
© 2013 Adobe Systems Incorporated. All Rights Reserved.
Futures: Building, The
template <typename> class packaged_task; //not defined
template <typename R>
class future {
shared_ptr</* ... */> _p;
public:
future() = default;
template <typename F>
auto then(F&& f) { }
const R& get() const { }
};
template<typename R, typename ...Args >
class packaged_task<R (Args...)> {
weak_ptr</* ... */> _p;
public:
packaged_task() = default;
template <typename... A>
void operator()(A&&... args) const { }
};
52
© 2013 Adobe Systems Incorporated. All Rights Reserved.
Futures: Building, The
template <typename> class packaged_task; //not defined
template <typename R>
class future {
shared_ptr</* ... */> _p;
public:
future() = default;
template <typename F>
auto then(F&& f) { }
const R& get() const { }
};
template<typename R, typename ...Args >
class packaged_task<R (Args...)> {
weak_ptr</* ... */> _p;
public:
packaged_task() = default;
template <typename... A>
void operator()(A&&... args) const { }
};
52
© 2013 Adobe Systems Incorporated. All Rights Reserved.
Futures: Building, The
template <typename> class packaged_task; //not defined
template <typename R>
class future {
shared_ptr</* ... */> _p;
public:
future() = default;
template <typename F>
auto then(F&& f) { }
const R& get() const { }
};
template<typename R, typename ...Args >
class packaged_task<R (Args...)> {
weak_ptr</* ... */> _p;
public:
packaged_task() = default;
template <typename... A>
void operator()(A&&... args) const { }
};
52
© 2013 Adobe Systems Incorporated. All Rights Reserved.
Futures: Building, The
template <typename> class packaged_task; //not defined
template <typename R>
class future {
shared_ptr</* ... */> _p;
public:
future() = default;
template <typename F>
auto then(F&& f) { }
const R& get() const { }
};
template<typename R, typename ...Args >
class packaged_task<R (Args...)> {
weak_ptr</* ... */> _p;
public:
packaged_task() = default;
template <typename... A>
void operator()(A&&... args) const { }
};
52
© 2013 Adobe Systems Incorporated. All Rights Reserved.
template <typename> class packaged_task; //not defined
template <typename> class future;
template <typename S, typename F>
auto package(F&& f) -> pair<packaged_task<S>, future<result_of_t_<S>>>;
template <typename R>
class future {
shared_ptr</* ... */> _p;
template <typename S, typename F>
friend auto package(F&& f) -> pair<packaged_task<S>, future<result_of_t_<S>>>;
explicit future(shared_ptr</* ... */> p) : _p(move(p)) { }
/* ... */
};
template<typename R, typename ...Args >
class packaged_task<R (Args...)> {
weak_ptr</* ... */> _p;
template <typename S, typename F>
friend auto package(F&& f) -> pair<packaged_task<S>, future<result_of_t_<S>>>;
explicit packaged_task(weak_ptr</* ... */> p) : _p(move(p)) { }
/* ... */
};
Futures: Building, The
53
© 2013 Adobe Systems Incorporated. All Rights Reserved.
template <typename> class packaged_task; //not defined
template <typename> class future;
template <typename S, typename F>
auto package(F&& f) -> pair<packaged_task<S>, future<result_of_t_<S>>>;
template <typename R>
class future {
shared_ptr</* ... */> _p;
template <typename S, typename F>
friend auto package(F&& f) -> pair<packaged_task<S>, future<result_of_t_<S>>>;
explicit future(shared_ptr</* ... */> p) : _p(move(p)) { }
/* ... */
};
template<typename R, typename ...Args >
class packaged_task<R (Args...)> {
weak_ptr</* ... */> _p;
template <typename S, typename F>
friend auto package(F&& f) -> pair<packaged_task<S>, future<result_of_t_<S>>>;
explicit packaged_task(weak_ptr</* ... */> p) : _p(move(p)) { }
/* ... */
};
Futures: Building, The
53
© 2013 Adobe Systems Incorporated. All Rights Reserved.
template <typename> class packaged_task; //not defined
template <typename> class future;
template <typename S, typename F>
auto package(F&& f) -> pair<packaged_task<S>, future<result_of_t_<S>>>;
template <typename R>
class future {
shared_ptr</* ... */> _p;
template <typename S, typename F>
friend auto package(F&& f) -> pair<packaged_task<S>, future<result_of_t_<S>>>;
explicit future(shared_ptr</* ... */> p) : _p(move(p)) { }
/* ... */
};
template<typename R, typename ...Args >
class packaged_task<R (Args...)> {
weak_ptr</* ... */> _p;
template <typename S, typename F>
friend auto package(F&& f) -> pair<packaged_task<S>, future<result_of_t_<S>>>;
explicit packaged_task(weak_ptr</* ... */> p) : _p(move(p)) { }
/* ... */
};
Futures: Building, The
53
© 2013 Adobe Systems Incorporated. All Rights Reserved.
template <typename> class packaged_task; //not defined
template <typename> class future;
template <typename S, typename F>
auto package(F&& f) -> pair<packaged_task<S>, future<result_of_t_<S>>>;
template <typename R>
class future {
shared_ptr</* ... */> _p;
template <typename S, typename F>
friend auto package(F&& f) -> pair<packaged_task<S>, future<result_of_t_<S>>>;
explicit future(shared_ptr</* ... */> p) : _p(move(p)) { }
/* ... */
};
template<typename R, typename ...Args >
class packaged_task<R (Args...)> {
weak_ptr</* ... */> _p;
template <typename S, typename F>
friend auto package(F&& f) -> pair<packaged_task<S>, future<result_of_t_<S>>>;
explicit packaged_task(weak_ptr</* ... */> p) : _p(move(p)) { }
/* ... */
};
Futures: Building, The
53
© 2013 Adobe Systems Incorporated. All Rights Reserved.
template <typename S, typename F>
auto package(F&& f) -> pair<packaged_task<S>, future<result_of_t_<S>>> {
auto p = make_shared<shared<S>>(forward<F>(f));
return make_pair(packaged_task<S>(p), future<result_of_t_<S>>(p));
}
Futures: Building, The
54
© 2013 Adobe Systems Incorporated. All Rights Reserved.
template <typename S, typename F>
auto package(F&& f) -> pair<packaged_task<S>, future<result_of_t_<S>>> {
auto p = make_shared<shared<S>>(forward<F>(f));
return make_pair(packaged_task<S>(p), future<result_of_t_<S>>(p));
}
Futures: Building, The
54
package<int(double)>(f) -> { void(double), future<int> }
© 2013 Adobe Systems Incorporated. All Rights Reserved.
template <typename R>
struct shared_base {
vector<R> _r; // optional
mutex _mutex;
condition_variable _ready;
vector<function<void()>> _then;
virtual ~shared_base() { }
/* ... */
};
template <typename> struct shared; // not defined
template <typename R, typename... Args>
struct shared<R(Args...)> : shared_base<R> {
function<R(Args...)> _f;
template<typename F>
shared(F&& f) : _f(forward<F>(f)) { }
/* ... */
};
Futures: Building, The
55
© 2013 Adobe Systems Incorporated. All Rights Reserved.
template <typename R>
struct shared_base {
vector<R> _r; // optional
mutex _mutex;
condition_variable _ready;
vector<function<void()>> _then;
virtual ~shared_base() { }
/* ... */
};
template <typename> struct shared; // not defined
template <typename R, typename... Args>
struct shared<R(Args...)> : shared_base<R> {
function<R(Args...)> _f;
template<typename F>
shared(F&& f) : _f(forward<F>(f)) { }
/* ... */
};
Futures: Building, The
55
© 2013 Adobe Systems Incorporated. All Rights Reserved.
template <typename R>
struct shared_base {
vector<R> _r; // optional
mutex _mutex;
condition_variable _ready;
vector<function<void()>> _then;
virtual ~shared_base() { }
/* ... */
};
template <typename> struct shared; // not defined
template <typename R, typename... Args>
struct shared<R(Args...)> : shared_base<R> {
function<R(Args...)> _f;
template<typename F>
shared(F&& f) : _f(forward<F>(f)) { }
/* ... */
};
Futures: Building, The
55
© 2013 Adobe Systems Incorporated. All Rights Reserved.
template<typename R, typename ...Args >
class packaged_task<R (Args...)> {
weak_ptr<shared<R(Args...)>> _p;
template <typename S, typename F>
friend auto package(F&& f) -> pair<packaged_task<S>, future<result_of_t_<S>>>;
explicit packaged_task(weak_ptr<shared<R(Args...)>> p) : _p(move(p)) { }
public:
packaged_task() = default;
template <typename... A>
void operator()(A&&... args) const {
auto p = _p.lock();
if (p) (*p)(forward<A>(args)...);
}
};
Futures: Building, The
56
© 2013 Adobe Systems Incorporated. All Rights Reserved.
template<typename R, typename ...Args >
class packaged_task<R (Args...)> {
weak_ptr<shared<R(Args...)>> _p;
template <typename S, typename F>
friend auto package(F&& f) -> pair<packaged_task<S>, future<result_of_t_<S>>>;
explicit packaged_task(weak_ptr<shared<R(Args...)>> p) : _p(move(p)) { }
public:
packaged_task() = default;
template <typename... A>
void operator()(A&&... args) const {
auto p = _p.lock();
if (p) (*p)(forward<A>(args)...);
}
};
Futures: Building, The
56
© 2013 Adobe Systems Incorporated. All Rights Reserved.
template<typename R, typename ...Args >
class packaged_task<R (Args...)> {
weak_ptr<shared<R(Args...)>> _p;
template <typename S, typename F>
friend auto package(F&& f) -> pair<packaged_task<S>, future<result_of_t_<S>>>;
explicit packaged_task(weak_ptr<shared<R(Args...)>> p) : _p(move(p)) { }
public:
packaged_task() = default;
template <typename... A>
void operator()(A&&... args) const {
auto p = _p.lock();
if (p) (*p)(forward<A>(args)...);
}
};
Futures: Building, The
56
© 2013 Adobe Systems Incorporated. All Rights Reserved.
template <typename R, typename... Args>
struct shared<R(Args...)> : shared_base<R> {
function<R(Args...)> _f;
template<typename F>
shared(F&& f) : _f(forward<F>(f)) { }
template <typename... A>
void operator()(A&&... args) {
this->set(_f(forward<A>(args)...));
_f = nullptr;
}
};
Futures: Building, The
57
© 2013 Adobe Systems Incorporated. All Rights Reserved.
template <typename R, typename... Args>
struct shared<R(Args...)> : shared_base<R> {
function<R(Args...)> _f;
template<typename F>
shared(F&& f) : _f(forward<F>(f)) { }
template <typename... A>
void operator()(A&&... args) {
this->set(_f(forward<A>(args)...));
_f = nullptr;
}
};
Futures: Building, The
57
© 2013 Adobe Systems Incorporated. All Rights Reserved.
template <typename R>
struct shared_base {
vector<R> _r; // optional
mutex _mutex;
condition_variable _ready;
vector<function<void()>> _then;
virtual ~shared_base() { }
void set(R&& r) {
vector<function<void()>> then;
{
lock_t lock{_mutex};
_r.push_back(move(r));
swap(_then, then);
}
_ready.notify_all();
for (const auto& f : then) _system.async_(move(f));
}
};
Futures: Building, The
58
© 2013 Adobe Systems Incorporated. All Rights Reserved.
template <typename R>
struct shared_base {
vector<R> _r; // optional
mutex _mutex;
condition_variable _ready;
vector<function<void()>> _then;
virtual ~shared_base() { }
void set(R&& r) {
vector<function<void()>> then;
{
lock_t lock{_mutex};
_r.push_back(move(r));
swap(_then, then);
}
_ready.notify_all();
for (const auto& f : then) _system.async_(move(f));
}
};
Futures: Building, The
58
© 2013 Adobe Systems Incorporated. All Rights Reserved.
template <typename R>
class future {
shared_ptr<shared_base<R>> _p;
template <typename S, typename F>
friend auto package(F&& f) -> pair<packaged_task<S>, future<result_of_t_<S>>>;
explicit future(shared_ptr<shared_base<R>> p) : _p(move(p)) { }
public:
future() = default;
template <typename F>
auto then(F&& f) {
auto pack = package<result_of_t<F(R)>()>([p = _p, f = forward<F>(f)](){
return f(p->_r.back());
});
_p->then(move(pack.first));
return pack.second;
}
const R& get() const { return _p->get(); }
};
Futures: Building, The
59
© 2013 Adobe Systems Incorporated. All Rights Reserved.
template <typename R>
class future {
shared_ptr<shared_base<R>> _p;
template <typename S, typename F>
friend auto package(F&& f) -> pair<packaged_task<S>, future<result_of_t_<S>>>;
explicit future(shared_ptr<shared_base<R>> p) : _p(move(p)) { }
public:
future() = default;
template <typename F>
auto then(F&& f) {
auto pack = package<result_of_t<F(R)>()>([p = _p, f = forward<F>(f)](){
return f(p->_r.back());
});
_p->then(move(pack.first));
return pack.second;
}
const R& get() const { return _p->get(); }
};
Futures: Building, The
59
© 2013 Adobe Systems Incorporated. All Rights Reserved.
template <typename R>
class future {
shared_ptr<shared_base<R>> _p;
template <typename S, typename F>
friend auto package(F&& f) -> pair<packaged_task<S>, future<result_of_t_<S>>>;
explicit future(shared_ptr<shared_base<R>> p) : _p(move(p)) { }
public:
future() = default;
template <typename F>
auto then(F&& f) {
auto pack = package<result_of_t<F(R)>()>([p = _p, f = forward<F>(f)](){
return f(p->_r.back());
});
_p->then(move(pack.first));
return pack.second;
}
const R& get() const { return _p->get(); }
};
Futures: Building, The
59
© 2013 Adobe Systems Incorporated. All Rights Reserved.
template <typename R>
class future {
shared_ptr<shared_base<R>> _p;
template <typename S, typename F>
friend auto package(F&& f) -> pair<packaged_task<S>, future<result_of_t_<S>>>;
explicit future(shared_ptr<shared_base<R>> p) : _p(move(p)) { }
public:
future() = default;
template <typename F>
auto then(F&& f) {
auto pack = package<result_of_t<F(R)>()>([p = _p, f = forward<F>(f)](){
return f(p->_r.back());
});
_p->then(move(pack.first));
return pack.second;
}
const R& get() const { return _p->get(); }
};
Futures: Building, The
59
© 2013 Adobe Systems Incorporated. All Rights Reserved.
template <typename R>
struct shared_base {
vector<R> _r; // optional
mutex _mutex;
condition_variable _ready;
vector<function<void()>> _then;
virtual ~shared_base() { }
void set(R&& r) { }
template <typename F>
void then(F&& f) {
bool resolved{false};
{
lock_t lock{_mutex};
if (_r.empty()) _then.push_back(forward<F>(f));
else resolved = true;
}
if (resolved) _system.async_(move(f));
}
const R& get() {
lock_t lock{_mutex};
while (_r.empty()) _ready.wait(lock);
return _r.back();
}
};
Futures: Building, The
60
© 2013 Adobe Systems Incorporated. All Rights Reserved.
template <typename R>
struct shared_base {
vector<R> _r; // optional
mutex _mutex;
condition_variable _ready;
vector<function<void()>> _then;
virtual ~shared_base() { }
void set(R&& r) { }
template <typename F>
void then(F&& f) {
bool resolved{false};
{
lock_t lock{_mutex};
if (_r.empty()) _then.push_back(forward<F>(f));
else resolved = true;
}
if (resolved) _system.async_(move(f));
}
const R& get() {
lock_t lock{_mutex};
while (_r.empty()) _ready.wait(lock);
return _r.back();
}
};
Futures: Building, The
60
© 2013 Adobe Systems Incorporated. All Rights Reserved.
template <typename R>
struct shared_base {
vector<R> _r; // optional
mutex _mutex;
condition_variable _ready;
vector<function<void()>> _then;
virtual ~shared_base() { }
void set(R&& r) { }
template <typename F>
void then(F&& f) {
bool resolved{false};
{
lock_t lock{_mutex};
if (_r.empty()) _then.push_back(forward<F>(f));
else resolved = true;
}
if (resolved) _system.async_(move(f));
}
const R& get() {
lock_t lock{_mutex};
while (_r.empty()) _ready.wait(lock);
return _r.back();
}
};
Futures: Building, The
60
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Futures
61
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Futures
61
shared
shared
shared
© 2013 Adobe Systems Incorporated. All Rights Reserved.
template <typename F, typename ...Args>
auto async(F&& f, Args&&... args)
{
using result_type = result_of_t<F (Args...)>;
using packaged_type = packaged_task<result_type()>;
auto pack = package<result_type()>(bind(forward<F>(f), forward<Args>(args)...));
_system.async_(move(get<0>(pack)));
return get<1>(pack);
}
Futures: Building, The
62
© 2013 Adobe Systems Incorporated. All Rights Reserved.
Futures: Continuations
future<cpp_int> x = async([]{ return fibonacci<cpp_int>(100); });
future<cpp_int> y = x.then([](const cpp_int& x){ return cpp_int(x * 2); });
future<cpp_int> z = x.then([](const cpp_int& x){ return cpp_int(x / 15); });
cout << y.get() << endl;
cout << z.get() << endl;
63
© 2013 Adobe Systems Incorporated. All Rights Reserved.
Futures: Continuations
future<cpp_int> x = async([]{ return fibonacci<cpp_int>(100); });
future<cpp_int> y = x.then([](const cpp_int& x){ return cpp_int(x * 2); });
future<cpp_int> z = x.then([](const cpp_int& x){ return cpp_int(x / 15); });
cout << y.get() << endl;
cout << z.get() << endl;
63
708449696358523830150
23614989878617461005
© 2014 Adobe Systems Incorporated. All Rights Reserved.
Property Models
64
© 2013 Adobe Systems Incorporated. All Rights Reserved.
What if we persist the graph?
65
© 2013 Adobe Systems Incorporated. All Rights Reserved.
What if we persist the graph?
! Allow multiple invocations of the tasks by setting the source values
! Each change triggers a notification to the sink values
! This is a reactive programming model and futures are known as behaviors
66
© 2013 Adobe Systems Incorporated. All Rights Reserved.
How do the graphs change during execution?
67
© 2013 Adobe Systems Incorporated. All Rights Reserved.
Property Model
68
a
c
R{a,b,c} b
© 2013 Adobe Systems Incorporated. All Rights Reserved.
A function is a directed relationship
! We can remove the arrows by providing a package of functions to represent the relationship
! a = b * c

b = a / c

c = a / b
! This forms a type of constraint system called a property model
! Flow is determined by value, or cell, priority
! Cells can only have one in-edge for a given flow or the system is over constrained
69
© 2013 Adobe Systems Incorporated. All Rights Reserved.
Property Model
70
sink
source
source
sink
© 2013 Adobe Systems Incorporated. All Rights Reserved.
Property Models
! Reflowing a property model doesn’t require all relationships to be resolved
! The task representing them can still be executing concurrently
! This creates a single dependency graph that is appended to for each new flow and is pruned and unravels as
tasks are complete
71
© 2013 Adobe Systems Incorporated. All Rights Reserved.
Property Model
72
source
source
sink
sink
source
sink
sink
© 2013 Adobe Systems Incorporated. All Rights Reserved.
Final Thoughts
! Perhaps representing such systems as if it where imperative code is not the correct approach
! Instead the a graph description can be compiled and statically validated
73
© 2014 Adobe Systems Incorporated. All Rights Reserved.

More Related Content

PDF
Joel Falcou, Boost.SIMD
PPTX
PVS-Studio. Static code analyzer. Windows/Linux, C/C++/C#. 2017
PPTX
Gor Nishanov, C++ Coroutines – a negative overhead abstraction
PPTX
soscon2018 - Tracing for fun and profit
PPTX
C++17 now
PDF
Architecture for Massively Parallel HDL Simulations
PDF
Kirk Shoop, Reactive programming in C++
PDF
Functional Reactive Programming on Android
Joel Falcou, Boost.SIMD
PVS-Studio. Static code analyzer. Windows/Linux, C/C++/C#. 2017
Gor Nishanov, C++ Coroutines – a negative overhead abstraction
soscon2018 - Tracing for fun and profit
C++17 now
Architecture for Massively Parallel HDL Simulations
Kirk Shoop, Reactive programming in C++
Functional Reactive Programming on Android

What's hot (20)

PDF
Антон Бикинеев, Writing good std::future&lt; C++ >
PDF
JVM Mechanics: When Does the JVM JIT & Deoptimize?
PDF
Clang tidy
PDF
Verilator: Fast, Free, But for Me?
PPTX
PVS-Studio 5.00, a solution for developers of modern resource-intensive appl...
PPTX
Code generation with javac plugin
PDF
Global Interpreter Lock: Episode I - Break the Seal
PDF
Checking the Cross-Platform Framework Cocos2d-x
PDF
How to make a large C++-code base manageable
PPTX
PVS-Studio for Linux (CoreHard presentation)
PDF
Introduction to web programming for java and c# programmers by @drpicox
PPTX
Js tacktalk team dev js testing performance
PDF
PVS-Studio and Continuous Integration: TeamCity. Analysis of the Open RollerC...
PDF
Objective-C Runtime overview
PDF
The Ring programming language version 1.6 book - Part 184 of 189
PDF
The Ring programming language version 1.10 book - Part 102 of 212
PPTX
NDC 2011, C++ 프로그래머를 위한 C#
PPTX
Concurrency in Programming Languages
PPTX
Quickly Testing Qt Desktop Applications
PPTX
Static Code Analysis for Projects, Built on Unreal Engine
Антон Бикинеев, Writing good std::future&lt; C++ >
JVM Mechanics: When Does the JVM JIT & Deoptimize?
Clang tidy
Verilator: Fast, Free, But for Me?
PVS-Studio 5.00, a solution for developers of modern resource-intensive appl...
Code generation with javac plugin
Global Interpreter Lock: Episode I - Break the Seal
Checking the Cross-Platform Framework Cocos2d-x
How to make a large C++-code base manageable
PVS-Studio for Linux (CoreHard presentation)
Introduction to web programming for java and c# programmers by @drpicox
Js tacktalk team dev js testing performance
PVS-Studio and Continuous Integration: TeamCity. Analysis of the Open RollerC...
Objective-C Runtime overview
The Ring programming language version 1.6 book - Part 184 of 189
The Ring programming language version 1.10 book - Part 102 of 212
NDC 2011, C++ 프로그래머를 위한 C#
Concurrency in Programming Languages
Quickly Testing Qt Desktop Applications
Static Code Analysis for Projects, Built on Unreal Engine
Ad

Similar to Better Code: Concurrency (20)

PDF
A Survey on in-a-box parallel computing and its implications on system softwa...
PDF
Trip down the GPU lane with Machine Learning
PPT
Threading Successes 05 Smoke
PDF
Use C++ and Intel® Threading Building Blocks (Intel® TBB) for Hardware Progra...
PPT
Coding for multiple cores
PDF
CUDA by Example : Thread Cooperation : Notes
PDF
Introduction to Parallel Computing
PPTX
Gpgpu intro
PDF
Dark Silicon, Mobile Devices, and Possible Open-Source Solutions
PDF
OpenMP tasking model: from the standard to the classroom
PDF
parallelizing_the_naughty_dog_engine_using_fibers.pdf
PPTX
17. thread and deadlock
PDF
Open CL For Speedup Workshop
PDF
Intel's Presentation in SIGGRAPH OpenCL BOF
PPT
3. CUDA_PPT.ppt info abt threads in cuda
PPT
Migration To Multi Core - Parallel Programming Models
PPTX
gpu1 - Modern Systems GPU Introduction.pptx
PPTX
Cuda meetup presentation 5
PDF
Nvidia cuda tutorial_no_nda_apr08
A Survey on in-a-box parallel computing and its implications on system softwa...
Trip down the GPU lane with Machine Learning
Threading Successes 05 Smoke
Use C++ and Intel® Threading Building Blocks (Intel® TBB) for Hardware Progra...
Coding for multiple cores
CUDA by Example : Thread Cooperation : Notes
Introduction to Parallel Computing
Gpgpu intro
Dark Silicon, Mobile Devices, and Possible Open-Source Solutions
OpenMP tasking model: from the standard to the classroom
parallelizing_the_naughty_dog_engine_using_fibers.pdf
17. thread and deadlock
Open CL For Speedup Workshop
Intel's Presentation in SIGGRAPH OpenCL BOF
3. CUDA_PPT.ppt info abt threads in cuda
Migration To Multi Core - Parallel Programming Models
gpu1 - Modern Systems GPU Introduction.pptx
Cuda meetup presentation 5
Nvidia cuda tutorial_no_nda_apr08
Ad

More from Platonov Sergey (20)

PPTX
Евгений Зуев, С++ в России: Стандарт языка и его реализация
PPTX
Алексей Кутумов, C++ без исключений, часть 3
PPTX
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
PPT
Евгений Крутько, Многопоточные вычисления, современный подход.
PDF
Тененёв Анатолий, Boost.Asio в алгоритмической торговле
PPTX
Павел Беликов, Опыт мигрирования крупного проекта с Windows-only на Linux
PDF
Дмитрий Кашицын, Вывод типов в динамических и не очень языках II
PDF
Дмитрий Кашицын, Вывод типов в динамических и не очень языках I
PDF
QML\Qt Quick на практике
PDF
Визуализация автомобильных маршрутов
PDF
Функциональный микроскоп: линзы в C++
PDF
C++ exceptions
PPTX
Как мы уменьшили количество ошибок в Unreal Engine с помощью статического ана...
PDF
HPX: C++11 runtime система для параллельных и распределённых вычислений
PPTX
Ranges calendar-novosibirsk-2015-08
PDF
Использование maven для сборки больших модульных c++ проектов на примере Odin...
PDF
Дракон в мешке: от LLVM к C++ и проблемам неопределенного поведения
PDF
One definition rule - что это такое, и как с этим жить
PDF
DI в C++ тонкости и нюансы
PPTX
Аскетичная разработка браузера
Евгений Зуев, С++ в России: Стандарт языка и его реализация
Алексей Кутумов, C++ без исключений, часть 3
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Евгений Крутько, Многопоточные вычисления, современный подход.
Тененёв Анатолий, Boost.Asio в алгоритмической торговле
Павел Беликов, Опыт мигрирования крупного проекта с Windows-only на Linux
Дмитрий Кашицын, Вывод типов в динамических и не очень языках II
Дмитрий Кашицын, Вывод типов в динамических и не очень языках I
QML\Qt Quick на практике
Визуализация автомобильных маршрутов
Функциональный микроскоп: линзы в C++
C++ exceptions
Как мы уменьшили количество ошибок в Unreal Engine с помощью статического ана...
HPX: C++11 runtime система для параллельных и распределённых вычислений
Ranges calendar-novosibirsk-2015-08
Использование maven для сборки больших модульных c++ проектов на примере Odin...
Дракон в мешке: от LLVM к C++ и проблемам неопределенного поведения
One definition rule - что это такое, и как с этим жить
DI в C++ тонкости и нюансы
Аскетичная разработка браузера

Recently uploaded (20)

PDF
Design an Analysis of Algorithms II-SECS-1021-03
PPT
Introduction Database Management System for Course Database
PPTX
L1 - Introduction to python Backend.pptx
PDF
EN-Survey-Report-SAP-LeanIX-EA-Insights-2025.pdf
PDF
System and Network Administraation Chapter 3
PPTX
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
PPTX
Agentic AI : A Practical Guide. Undersating, Implementing and Scaling Autono...
PPTX
Lecture 3: Operating Systems Introduction to Computer Hardware Systems
PDF
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
PDF
Understanding Forklifts - TECH EHS Solution
PDF
Designing Intelligence for the Shop Floor.pdf
PDF
Softaken Excel to vCard Converter Software.pdf
PPTX
history of c programming in notes for students .pptx
PPTX
CHAPTER 2 - PM Management and IT Context
PDF
Navsoft: AI-Powered Business Solutions & Custom Software Development
PDF
Which alternative to Crystal Reports is best for small or large businesses.pdf
PDF
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
PDF
Why TechBuilder is the Future of Pickup and Delivery App Development (1).pdf
PPTX
VVF-Customer-Presentation2025-Ver1.9.pptx
PDF
How to Choose the Right IT Partner for Your Business in Malaysia
Design an Analysis of Algorithms II-SECS-1021-03
Introduction Database Management System for Course Database
L1 - Introduction to python Backend.pptx
EN-Survey-Report-SAP-LeanIX-EA-Insights-2025.pdf
System and Network Administraation Chapter 3
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
Agentic AI : A Practical Guide. Undersating, Implementing and Scaling Autono...
Lecture 3: Operating Systems Introduction to Computer Hardware Systems
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
Understanding Forklifts - TECH EHS Solution
Designing Intelligence for the Shop Floor.pdf
Softaken Excel to vCard Converter Software.pdf
history of c programming in notes for students .pptx
CHAPTER 2 - PM Management and IT Context
Navsoft: AI-Powered Business Solutions & Custom Software Development
Which alternative to Crystal Reports is best for small or large businesses.pdf
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
Why TechBuilder is the Future of Pickup and Delivery App Development (1).pdf
VVF-Customer-Presentation2025-Ver1.9.pptx
How to Choose the Right IT Partner for Your Business in Malaysia

Better Code: Concurrency

  • 1. © 2014 Adobe Systems Incorporated. All Rights Reserved. Better Code: Concurrency Sean Parent | Principal Scientist
  • 2. © 2014 Adobe Systems Incorporated. All Rights Reserved. Better Code ! Regular Type ! Goal: Implement Complete and Efficient Types ! Algorithms ! Goal: No Raw Loops ! Data Structures ! Goal: No Incidental Data Structures ! Runtime Polymorphism ! Goal: No Raw Pointers ! Concurrency ! Goal: No Raw Synchronization Primitives ! … 2
  • 3. © 2014 Adobe Systems Incorporated. All Rights Reserved. Common Themes ! Manage Relationships ! Understand the Fundamentals ! Code Simply 3
  • 4. © 2013 Adobe Systems Incorporated. All Rights Reserved. Demo 4
  • 5. © 2014 Adobe Systems Incorporated. All Rights Reserved. Concurrency ! Concurrency: when tasks start, run, and complete in overlapping time periods ! Parallelism: when two or more tasks execute simultaneously ! Why? ! Enable performance through parallelism ! Improve interactivity by handling user actions concurrent with processing and IO 5 http://docs.oracle.com/cd/E19455-01/806-5257/6je9h032b/index.html
  • 6. © 2013 Adobe Systems Incorporated. All Rights Reserved. No Raw Synchronization Primitives 6
  • 7. © 2013 Adobe Systems Incorporated. All Rights Reserved. What are raw synchronization primitives? ! Synchronization primitives are basic constructs such as: ! Mutex ! Atomic ! Semaphore ! Memory Fence ! Condition Variable 7
  • 8. © 2014 Adobe Systems Incorporated. All Rights Reserved. 8 Desktop Compute Power (8-core 3.5GHz Sandy Bridge + AMD Radeon 6950) 8
  • 9. © 2014 Adobe Systems Incorporated. All Rights Reserved. 8 Desktop Compute Power (8-core 3.5GHz Sandy Bridge + AMD Radeon 6950) 8 0 750 1500 2250 3000 GPU Vectorization Multi-thread Scalar (GFlops)
  • 10. © 2014 Adobe Systems Incorporated. All Rights Reserved. 8 Desktop Compute Power (8-core 3.5GHz Sandy Bridge + AMD Radeon 6950) 8 OpenGL OpenCL CUDA Direct Compute C++ AMP DirectX 0 750 1500 2250 3000 GPU Vectorization Multi-thread Scalar (GFlops)
  • 11. © 2014 Adobe Systems Incorporated. All Rights Reserved. 8 Desktop Compute Power (8-core 3.5GHz Sandy Bridge + AMD Radeon 6950) Intrinsics Auto-vectorization OpenCL 8 OpenGL OpenCL CUDA Direct Compute C++ AMP DirectX 0 750 1500 2250 3000 GPU Vectorization Multi-thread Scalar (GFlops)
  • 12. © 2014 Adobe Systems Incorporated. All Rights Reserved. 8 Desktop Compute Power (8-core 3.5GHz Sandy Bridge + AMD Radeon 6950) Intrinsics Auto-vectorization OpenCL 8 TBB GCD OpenMP C++11 OpenGL OpenCL CUDA Direct Compute C++ AMP DirectX 0 750 1500 2250 3000 GPU Vectorization Multi-thread Scalar (GFlops)
  • 13. © 2014 Adobe Systems Incorporated. All Rights Reserved. 8 Desktop Compute Power (8-core 3.5GHz Sandy Bridge + AMD Radeon 6950) Intrinsics Auto-vectorization OpenCL 8 Straight C++ TBB GCD OpenMP C++11 OpenGL OpenCL CUDA Direct Compute C++ AMP DirectX 0 750 1500 2250 3000 GPU Vectorization Multi-thread Scalar (GFlops)
  • 14. © 2014 Adobe Systems Incorporated. All Rights Reserved. Threads and Tasks ! Thread: Execution environment consisting of a stack and processor state running in parallel to other threads ! Task: A unit of work, often a function, to be executed on a thread ! Tasks are scheduled on a thread pool to optimize machine utilization 9
  • 15. © 2014 Adobe Systems Incorporated. All Rights Reserved. C++14 and Tasks ! C++14 does not have a task system ! Threads ! Futures (more on this) 10
  • 16. © 2014 Adobe Systems Incorporated. All Rights Reserved. Amdahl’s Law 11 http://en.wikipedia.org/wiki/Amdahl%27s_law
  • 17. © 2014 Adobe Systems Incorporated. All Rights Reserved. Amdahl’s Law 12 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 Processors Performance
  • 18. © 2014 Adobe Systems Incorporated. All Rights Reserved. What Makes It Slow ! Starvation ! Latency ! Overhead ! Wait 13 Hartmut Kaiser - HPX
  • 19. © 2013 Adobe Systems Incorporated. All Rights Reserved. Why No Raw Synchronization Primitives? 14 Object thread thread thread
  • 20. © 2013 Adobe Systems Incorporated. All Rights Reserved. Why No Raw Synchronization Primitives? 14 Object thread thread thread STOP STOP GO
  • 21. © 2013 Adobe Systems Incorporated. All Rights Reserved. Why No Raw Synchronization Primitives? 14 Object thread thread thread STOP STOP GO
  • 22. © 2013 Adobe Systems Incorporated. All Rights Reserved. Why No Raw Synchronization Primitives? 14 Object thread thread thread STOP STOP GO
  • 23. © 2013 Adobe Systems Incorporated. All Rights Reserved. Minimize Locks 15 STOP
  • 24. © 2013 Adobe Systems Incorporated. All Rights Reserved. Minimize Locks 15 STOP
  • 25. © 2014 Adobe Systems Incorporated. All Rights Reserved. Building a Task System ! Portable Reference Implementation in C++14 ! Windows - Window Thread Pool and PPL ! Apple - Grand Central Dispatch (libdispatch) ! open source, runs on Linux and Android ! Intel TBB - many platforms ! open source ! HPX - many platforms ! open source 16
  • 26. © 2014 Adobe Systems Incorporated. All Rights Reserved. Building a Task System 17 http://docs.oracle.com/cd/E19253-01/816-5137/ggedn/index.html Core Core Core… Thread Thread Thread . . . Task Task Task Task
  • 27. © 2014 Adobe Systems Incorporated. All Rights Reserved. Building a Task System 18
  • 28. © 2014 Adobe Systems Incorporated. All Rights Reserved. Building a Task System using lock_t = unique_lock<mutex>; 18
  • 29. © 2014 Adobe Systems Incorporated. All Rights Reserved. Building a Task System using lock_t = unique_lock<mutex>; class notification_queue { deque<function<void()>> _q; mutex _mutex; condition_variable _ready; 18
  • 30. © 2014 Adobe Systems Incorporated. All Rights Reserved. Building a Task System using lock_t = unique_lock<mutex>; class notification_queue { deque<function<void()>> _q; mutex _mutex; condition_variable _ready; public: void pop(function<void()>& x) { lock_t lock{_mutex}; while (_q.empty()) _ready.wait(lock); x = move(_q.front()); _q.pop_front(); } 18
  • 31. © 2014 Adobe Systems Incorporated. All Rights Reserved. Building a Task System using lock_t = unique_lock<mutex>; class notification_queue { deque<function<void()>> _q; mutex _mutex; condition_variable _ready; public: void pop(function<void()>& x) { lock_t lock{_mutex}; while (_q.empty()) _ready.wait(lock); x = move(_q.front()); _q.pop_front(); } template<typename F> void push(F&& f) { { lock_t lock{_mutex}; _q.emplace_back(forward<F>(f)); } _ready.notify_one(); } }; 18
  • 32. © 2014 Adobe Systems Incorporated. All Rights Reserved. Building a Task System 19
  • 33. © 2014 Adobe Systems Incorporated. All Rights Reserved. Building a Task System class task_system { const unsigned _count{thread::hardware_concurrency()}; vector<thread> _threads; notification_queue _q; 19
  • 34. © 2014 Adobe Systems Incorporated. All Rights Reserved. Building a Task System class task_system { const unsigned _count{thread::hardware_concurrency()}; vector<thread> _threads; notification_queue _q; void run(unsigned i) { while (true) { function<void()> f; _q.pop(f); f(); } } 19
  • 35. © 2014 Adobe Systems Incorporated. All Rights Reserved. Building a Task System class task_system { const unsigned _count{thread::hardware_concurrency()}; vector<thread> _threads; notification_queue _q; void run(unsigned i) { while (true) { function<void()> f; _q.pop(f); f(); } } public: task_system() { for (unsigned n = 0; n != _count; ++n) { _threads.emplace_back([&, n]{ run(n); }); } } 19
  • 36. © 2014 Adobe Systems Incorporated. All Rights Reserved. Building a Task System class task_system { const unsigned _count{thread::hardware_concurrency()}; vector<thread> _threads; notification_queue _q; void run(unsigned i) { while (true) { function<void()> f; _q.pop(f); f(); } } public: task_system() { for (unsigned n = 0; n != _count; ++n) { _threads.emplace_back([&, n]{ run(n); }); } } ~task_system() { for (auto& e : _threads) e.join(); } 19
  • 37. © 2014 Adobe Systems Incorporated. All Rights Reserved. Building a Task System class task_system { const unsigned _count{thread::hardware_concurrency()}; vector<thread> _threads; notification_queue _q; void run(unsigned i) { while (true) { function<void()> f; _q.pop(f); f(); } } public: task_system() { for (unsigned n = 0; n != _count; ++n) { _threads.emplace_back([&, n]{ run(n); }); } } ~task_system() { for (auto& e : _threads) e.join(); } template <typename F> void async_(F&& f) { _q.push(forward<F>(f)); } }; 19
  • 38. © 2014 Adobe Systems Incorporated. All Rights Reserved. Building a Task System class notification_queue { deque<function<void()>> _q; bool _done{false}; mutex _mutex; condition_variable _ready; public: void done() { { unique_lock<mutex> lock{_mutex}; _done = true; } _ready.notify_all(); } bool pop(function<void()>& x) { lock_t lock{_mutex}; while (_q.empty() && !_done) _ready.wait(lock); if (_q.empty()) return false; x = move(_q.front()); _q.pop_front(); return true; } template<typename F> void push(F&& f) { { lock_t lock{_mutex}; _q.emplace_back(forward<F>(f)); 20
  • 39. © 2014 Adobe Systems Incorporated. All Rights Reserved. Building a Task System class notification_queue { deque<function<void()>> _q; bool _done{false}; mutex _mutex; condition_variable _ready; public: void done() { { unique_lock<mutex> lock{_mutex}; _done = true; } _ready.notify_all(); } bool pop(function<void()>& x) { lock_t lock{_mutex}; while (_q.empty() && !_done) _ready.wait(lock); if (_q.empty()) return false; x = move(_q.front()); _q.pop_front(); return true; } template<typename F> void push(F&& f) { { lock_t lock{_mutex}; _q.emplace_back(forward<F>(f)); 20
  • 40. © 2014 Adobe Systems Incorporated. All Rights Reserved. Building a Task System class notification_queue { deque<function<void()>> _q; bool _done{false}; mutex _mutex; condition_variable _ready; public: void done() { { unique_lock<mutex> lock{_mutex}; _done = true; } _ready.notify_all(); } bool pop(function<void()>& x) { lock_t lock{_mutex}; while (_q.empty() && !_done) _ready.wait(lock); if (_q.empty()) return false; x = move(_q.front()); _q.pop_front(); return true; } template<typename F> void push(F&& f) { { lock_t lock{_mutex}; _q.emplace_back(forward<F>(f)); 20
  • 41. © 2014 Adobe Systems Incorporated. All Rights Reserved. Building a Task System class notification_queue { deque<function<void()>> _q; bool _done{false}; mutex _mutex; condition_variable _ready; public: void done() { { unique_lock<mutex> lock{_mutex}; _done = true; } _ready.notify_all(); } bool pop(function<void()>& x) { lock_t lock{_mutex}; while (_q.empty() && !_done) _ready.wait(lock); if (_q.empty()) return false; x = move(_q.front()); _q.pop_front(); return true; } template<typename F> void push(F&& f) { { lock_t lock{_mutex}; _q.emplace_back(forward<F>(f)); 20
  • 42. © 2014 Adobe Systems Incorporated. All Rights Reserved. Building a Task System 21 Core Core Core… Thread Thread Thread . . . Task Task Task Task
  • 43. © 2014 Adobe Systems Incorporated. All Rights Reserved. Building a Task System 21 Core Core Core… Thread Thread Thread . . . Task Task Task Task
  • 44. © 2013 Adobe Systems Incorporated. All Rights Reserved. Why No Raw Synchronization Primitives? 22 Object thread thread thread
  • 45. © 2013 Adobe Systems Incorporated. All Rights Reserved. Why No Raw Synchronization Primitives? 22 Object thread thread thread STOP STOP GO
  • 46. © 2013 Adobe Systems Incorporated. All Rights Reserved. Why No Raw Synchronization Primitives? 22 Object thread thread thread STOP STOP GO
  • 47. © 2014 Adobe Systems Incorporated. All Rights Reserved. Building a Task System 23 Core Core Core… Thread Thread Thread . . . Task Task Task Task
  • 48. © 2014 Adobe Systems Incorporated. All Rights Reserved. Building a Task System 23 Core Core Core… Thread Thread Thread . . . Task Task Task Task
  • 49. © 2014 Adobe Systems Incorporated. All Rights Reserved. Building a Task System 24 Core Core Core… Thread Thread Thread . . . Task Task Task . . . Task Task Task . . . Task Task Task Task Scheduler
  • 50. © 2014 Adobe Systems Incorporated. All Rights Reserved. Building a Task System class task_system { const unsigned _count{thread::hardware_concurrency()}; vector<thread> _threads; vector<notification_queue> _q{_count}; atomic<unsigned> _index{0}; void run(unsigned i) { while (true) { function<void()> f; if (!_q[i].pop(f)) break; f(); } } public: task_system() { } ~task_system() { for (auto& e : _q) e.done(); for (auto& e : _threads) e.join(); } template <typename F> void async_(F&& f) { auto i = _index++; _q[i % _count].push(forward<F>(f)); } }; 25
  • 51. © 2014 Adobe Systems Incorporated. All Rights Reserved. Building a Task System class task_system { const unsigned _count{thread::hardware_concurrency()}; vector<thread> _threads; vector<notification_queue> _q{_count}; atomic<unsigned> _index{0}; void run(unsigned i) { while (true) { function<void()> f; if (!_q[i].pop(f)) break; f(); } } public: task_system() { } ~task_system() { for (auto& e : _q) e.done(); for (auto& e : _threads) e.join(); } template <typename F> void async_(F&& f) { auto i = _index++; _q[i % _count].push(forward<F>(f)); } }; 25
  • 52. © 2014 Adobe Systems Incorporated. All Rights Reserved. Building a Task System class task_system { const unsigned _count{thread::hardware_concurrency()}; vector<thread> _threads; vector<notification_queue> _q{_count}; atomic<unsigned> _index{0}; void run(unsigned i) { while (true) { function<void()> f; if (!_q[i].pop(f)) break; f(); } } public: task_system() { } ~task_system() { for (auto& e : _q) e.done(); for (auto& e : _threads) e.join(); } template <typename F> void async_(F&& f) { auto i = _index++; _q[i % _count].push(forward<F>(f)); } }; 25
  • 53. © 2014 Adobe Systems Incorporated. All Rights Reserved. Building a Task System class task_system { const unsigned _count{thread::hardware_concurrency()}; vector<thread> _threads; vector<notification_queue> _q{_count}; atomic<unsigned> _index{0}; void run(unsigned i) { while (true) { function<void()> f; if (!_q[i].pop(f)) break; f(); } } public: task_system() { } ~task_system() { for (auto& e : _q) e.done(); for (auto& e : _threads) e.join(); } template <typename F> void async_(F&& f) { auto i = _index++; _q[i % _count].push(forward<F>(f)); } }; 25
  • 54. © 2014 Adobe Systems Incorporated. All Rights Reserved. Building a Task System class task_system { const unsigned _count{thread::hardware_concurrency()}; vector<thread> _threads; vector<notification_queue> _q{_count}; atomic<unsigned> _index{0}; void run(unsigned i) { while (true) { function<void()> f; if (!_q[i].pop(f)) break; f(); } } public: task_system() { } ~task_system() { for (auto& e : _q) e.done(); for (auto& e : _threads) e.join(); } template <typename F> void async_(F&& f) { auto i = _index++; _q[i % _count].push(forward<F>(f)); } }; 25
  • 55. © 2014 Adobe Systems Incorporated. All Rights Reserved. Building a Task System 26 Core Core Core… Thread Thread Thread . . . Task Task Task . . . Task Task Task . . . Task Task Task Task Scheduler
  • 56. © 2014 Adobe Systems Incorporated. All Rights Reserved. Building a Task System 26 Core Core Core… Thread Thread Thread . . . Task Task Task . . . Task Task Task . . . Task Task Task Task Scheduler
  • 57. © 2014 Adobe Systems Incorporated. All Rights Reserved. Building a Task System 27 Core Core Core… Thread Thread Thread . . . Task Task Task . . . Task Task Task . . . Task Task Task Task Scheduler Task Stealing
  • 58. © 2014 Adobe Systems Incorporated. All Rights Reserved. Building a Task System class notification_queue { deque<function<void()>> _q; bool _done{false}; mutex _mutex; condition_variable _ready; public: bool try_pop(function<void()>& x) { lock_t lock{_mutex, try_to_lock}; if (!lock || _q.empty()) return false; x = move(_q.front()); _q.pop_front(); return true; } template<typename F> bool try_push(F&& f) { { lock_t lock{_mutex, try_to_lock}; if (!lock) return false; _q.emplace_back(forward<F>(f)); } _ready.notify_one(); return true; } void done() { { unique_lock<mutex> lock{_mutex}; 28
  • 59. © 2014 Adobe Systems Incorporated. All Rights Reserved. Building a Task System class notification_queue { deque<function<void()>> _q; bool _done{false}; mutex _mutex; condition_variable _ready; public: bool try_pop(function<void()>& x) { lock_t lock{_mutex, try_to_lock}; if (!lock || _q.empty()) return false; x = move(_q.front()); _q.pop_front(); return true; } template<typename F> bool try_push(F&& f) { { lock_t lock{_mutex, try_to_lock}; if (!lock) return false; _q.emplace_back(forward<F>(f)); } _ready.notify_one(); return true; } void done() { { unique_lock<mutex> lock{_mutex}; 28
  • 60. © 2014 Adobe Systems Incorporated. All Rights Reserved. Building a Task System class notification_queue { deque<function<void()>> _q; bool _done{false}; mutex _mutex; condition_variable _ready; public: bool try_pop(function<void()>& x) { lock_t lock{_mutex, try_to_lock}; if (!lock || _q.empty()) return false; x = move(_q.front()); _q.pop_front(); return true; } template<typename F> bool try_push(F&& f) { { lock_t lock{_mutex, try_to_lock}; if (!lock) return false; _q.emplace_back(forward<F>(f)); } _ready.notify_one(); return true; } void done() { { unique_lock<mutex> lock{_mutex}; 28
  • 61. © 2014 Adobe Systems Incorporated. All Rights Reserved. Building a Task System void run(unsigned i) { while (true) { function<void()> f; for (unsigned n = 0; n != _count; ++n) { if (_q[(i + n) % _count].try_pop(f)) break; } if (!f && !_q[i].pop(f)) break; f(); } } public: task_system() { } ~task_system() { } template <typename F> void async_(F&& f) { auto i = _index++; for (unsigned n = 0; n != _count; ++n) { if (_q[(i + n) % _count].try_push(forward<F>(f))) return; } _q[i % _count].push(forward<F>(f)); } }; 29
  • 62. © 2014 Adobe Systems Incorporated. All Rights Reserved. Building a Task System void run(unsigned i) { while (true) { function<void()> f; for (unsigned n = 0; n != _count; ++n) { if (_q[(i + n) % _count].try_pop(f)) break; } if (!f && !_q[i].pop(f)) break; f(); } } public: task_system() { } ~task_system() { } template <typename F> void async_(F&& f) { auto i = _index++; for (unsigned n = 0; n != _count; ++n) { if (_q[(i + n) % _count].try_push(forward<F>(f))) return; } _q[i % _count].push(forward<F>(f)); } }; 29
  • 63. © 2014 Adobe Systems Incorporated. All Rights Reserved. Building a Task System void run(unsigned i) { while (true) { function<void()> f; for (unsigned n = 0; n != _count; ++n) { if (_q[(i + n) % _count].try_pop(f)) break; } if (!f && !_q[i].pop(f)) break; f(); } } public: task_system() { } ~task_system() { } template <typename F> void async_(F&& f) { auto i = _index++; for (unsigned n = 0; n != _count; ++n) { if (_q[(i + n) % _count].try_push(forward<F>(f))) return; } _q[i % _count].push(forward<F>(f)); } }; 29
  • 64. © 2014 Adobe Systems Incorporated. All Rights Reserved. Building a Task System 30 Core Core Core… Thread Thread Thread . . . Task Task Task . . . Task Task Task . . . Task Task Task Task Scheduler Task Stealing
  • 65. © 2014 Adobe Systems Incorporated. All Rights Reserved. Building a Task System 30 Core Core Core… Thread Thread Thread . . . Task Task Task . . . Task Task Task . . . Task Task Task Task Scheduler Task Stealing
  • 66. © 2014 Adobe Systems Incorporated. All Rights Reserved. Task System ! Within a few percentage points of Apple’s GCD (libdispatch) under load ! Can be improved by spinning more on try_pop in run 31
  • 67. © 2014 Adobe Systems Incorporated. All Rights Reserved. Futures 32 future<cpp_int> x = async([]{ return fibonacci<cpp_int>(1'000'000); }); // Do Something cout << x.get() << endl;
  • 68. © 2014 Adobe Systems Incorporated. All Rights Reserved. Futures ! Fibonacci is often used as an example for parallel algorithms ! Please stop… 32 future<cpp_int> x = async([]{ return fibonacci<cpp_int>(1'000'000); }); // Do Something cout << x.get() << endl;
  • 69. © 2014 Adobe Systems Incorporated. All Rights Reserved. Public Service Announcement - How to Write Fibonacci template <typename T, typename N, typename O> T power(T x, N n, O op) { if (n == 0) return identity_element(op); while ((n & 1) == 0) { n >>= 1; x = op(x, x); } T result = x; n >>= 1; while (n != 0) { x = op(x, x); if ((n & 1) != 0) result = op(result, x); n >>= 1; } return result; } 33
  • 70. © 2014 Adobe Systems Incorporated. All Rights Reserved. Public Service Announcement - How to Write Fibonacci template <typename T, typename N, typename O> T power(T x, N n, O op) { if (n == 0) return identity_element(op); while ((n & 1) == 0) { n >>= 1; x = op(x, x); } T result = x; n >>= 1; while (n != 0) { x = op(x, x); if ((n & 1) != 0) result = op(result, x); n >>= 1; } return result; } 33 Egyptian Multiplication (Russian Peasant Algorithm) See “From Mathematics to Generic Programming” - Alex Stepanov and Dan Rose
  • 71. © 2014 Adobe Systems Incorporated. All Rights Reserved. Public Service Announcement - How to Write Fibonacci template <typename N> struct multiply_2x2 { array<N, 4> operator()(const array<N, 4>& x, const array<N, 4>& y) { return { x[0] * y[0] + x[1] * y[2], x[0] * y[1] + x[1] * y[3], x[2] * y[0] + x[3] * y[2], x[2] * y[1] + x[3] * y[3] }; } }; template <typename N> array<N, 4> identity_element(const multiply_2x2<N>&) { return { N(1), N(0), N(0), N(1) }; } template <typename R, typename N> R fibonacci(N n) { if (n == 0) return R(0); return power(array<R, 4>{ 1, 1, 1, 0 }, N(n - 1), multiply_2x2<R>())[0]; } 34
  • 72. © 2014 Adobe Systems Incorporated. All Rights Reserved. Futures 19532821287077577316320149475962563324435429965918733969534051945716252578870156947666419876341501461288795 24335220236084625510912019560233744015438115196636156919962125642894303370113827800638002767411527927466669 86557837931882283206127149758323033485489348957259923072291290192820926433162752173086146001791258204269965 99360209593392020051848620284024473431398113674187202038684801753185386211128781082406177413832935545616876 06454065125954718029126547942894036981659206361019359291352135410376799082940320155702716115395031975973247 78216295763162965335669477766328506234524559346064757502593581344345781676764625878859011372729907372947851 14480895724561915035070255895291168685500088020132334587472177947814475467920160901706425856293597475465327 57575740077432034913428785189795354304734560307765078938767286539166799232817449361991523768149557632085371 04785970618843873153058239562756087906310781900497516959470973671389174570455520213512335079440336071203050 41446852210415650373210679322756258647511914611417360349681217380234224786080292021093192496490409832397066 83247054441763512526732455275419501683845206023007394959854279298297831204382115757645787692495583351402522 15272066244180900325938075362849179668095297118507191379833678873770459913639333955814212036990261617972113 25091840023055327607104316478190974300434647793363287601469996128023925829471557316688943339455429292871877 48774789204296166356536610796023919702109728472966709427334586344798048633944635211654971507261342768205479 32093175079888010130416027982506354182344034558742236701282666356934611294613123128389060036547327660245693 15151850018328483150645480029978935985161237074046158229354440701748339514575869547491750264542126364262224 72060048855462589961190475892101224280542898621594646662478564373572217775549876087685912030118551635668902 01034463998397732663888903650784161807091545252992759735213957415477729146008794314339156060445825107823511 66271892637923313014643880597879468444879060576786297460989627426663569682474293386740207436559426057944790 71193052258931590719386545525880429139747140181849169733838138446154843063123649290835584278078456131936457 55911722136946338180311600307896211668652895953778436464402382516362449718197385444149563131714002850338928 22274134603018094224837216321854717270452813824078425638747365249141118080783866506339945376239206700513391 87333107136069698189628284763245423299306272870457991293245741167533902274499963096566680922262516468582544 55785134982414412726124015815753818098466667145006988839178551800894370189025721992485208742915560261917752 28124660628996787166529678487268484905041328497297712688011639978376434280202452251550102240354169885185375 01584673881194047619720619603126534496759917893244478170702904446589571950228809157793897642423751814020998 99958161231477902295781100168670186738619861797138139854666281969548553740707356228616165539428076418408092 12047932816683005984504787929406356318097479755152035094682765918741610907637506902765294367561539803261388 35
  • 73. © 2014 Adobe Systems Incorporated. All Rights Reserved. Futures 15790155892833100345673846243104676900000936756893803676769777642059716492347060997973282994459039755683869 10568541105888505197986232161807165960864316652383369579251545877324797429523572491518310013505994095431367 23454418539676396422570487868443336735568511535850565172490141772333018072390350689838662532338266203548476 87722321662223383305226882245421258277211223435986491973881404168406609216954760818955479619408040043497601 35646408461148077885537891122888139618703907906033147416881433658136276942006644505679690480702792206520855 12245086839375655196861305232092138041808273198852928058246964575561801618520046644949262341864859342928965 21378574554544426221453176445385228867960454072522804961741905198550911362542849130027243353553345377968558 49780195976636516290598457219043489821358221206856924121139313137132134865741440892670003665555632446499775 56853514681289887391700907057970839124191923062570547772748610990924519168225326823578140721238189631411471 29610287340041050015549547086272721534936510345705849389706515725684266079756708385889612130516276472992631 59674474594901199950849178952149715987731953191759591623424021718579696778102054496598766846143959650647332 21985323521378108187030642875506951890343587181633604126397675020909133548480151135951824112432636080497447 37395896608759569909256138919905403404664655310556021101996525724843421071082933739200159651403373870955680 75656822683537933983982488022723770319785461480932302347255796621173892988541730741484707211664044157057536 04582256143224299859780683239696543855523783781413866750792868372058020433472254190336846843017198934115689 96526838242546875 35 0.72s to calculate 208,988 digits
  • 74. © 2014 Adobe Systems Incorporated. All Rights Reserved. Futures 36 future<cpp_int> x = async([]{ return fibonacci<cpp_int>(1'000'000); }); // Do Something cout << x.get() << endl;
  • 75. f(…)->r © 2014 Adobe Systems Incorporated. All Rights Reserved. Futures 37
  • 76. f(…) r © 2014 Adobe Systems Incorporated. All Rights Reserved. Futures 37
  • 77. © 2014 Adobe Systems Incorporated. All Rights Reserved. Futures ! Futures allow minimal code transformations to express dependencies 38
  • 78. © 2014 Adobe Systems Incorporated. All Rights Reserved. Futures: What year is this? ! C++14 futures have: ! Exception Marshaling ! Sever Notification (broken promise) 39
  • 79. © 2014 Adobe Systems Incorporated. All Rights Reserved. Futures: What year is this? ! C++14 futures lack: ! Continuations - .then() ! Joins - when_all() ! Cancelation ! Progress Monitoring (Except Ready) ! … ! And C++14 futures don’t compose (easily) to add these features 40
  • 80. © 2014 Adobe Systems Incorporated. All Rights Reserved. Futures: Continuations 41
  • 81. © 2013 Adobe Systems Incorporated. All Rights Reserved. Futures: Continuations ! Blocking on std::future.get() has two problems ! One thread resource is consumed, increasing contention ! Any subsequent non-dependent calculations on the task are also blocked ! C++14 doesn’t have continuations ! GCD has serialized queues and groups ! PPL has chained tasks ! TBB has flow graphs ! TS Concurrency will have them ! Boost futures have them now 42
  • 82. © 2013 Adobe Systems Incorporated. All Rights Reserved. Futures: Continuations future<cpp_int> x = async([]{ return fibonacci<cpp_int>(1'000'000); }); future<void> y = x.then([](future<cpp_int> x){ cout << x.get() << endl; }); // Do something y.wait(); 43
  • 83. © 2014 Adobe Systems Incorporated. All Rights Reserved. Futures 44
  • 84. © 2013 Adobe Systems Incorporated. All Rights Reserved. Futures: Continuations auto x = async([]{ return fibonacci<cpp_int>(1'000'000); }); auto y = async([]{ return fibonacci<cpp_int>(2'000'000); }); auto z = when_all(std::move(x), std::move(y)).then([](auto f){ auto t = f.get(); return cpp_int(get<0>(t).get() * get<1>(t).get()); }); cout << z.get() << endl; 45
  • 85. © 2013 Adobe Systems Incorporated. All Rights Reserved. Futures: Continuations auto x = async([]{ return fibonacci<cpp_int>(1'000'000); }); auto y = async([]{ return fibonacci<cpp_int>(2'000'000); }); auto z = when_all(std::move(x), std::move(y)).then([](auto f){ auto t = f.get(); return cpp_int(get<0>(t).get() * get<1>(t).get()); }); cout << z.get() << endl; 45 f is a future tuple of futures
  • 86. © 2013 Adobe Systems Incorporated. All Rights Reserved. Futures: Continuations auto x = async([]{ return fibonacci<cpp_int>(1'000'000); }); auto y = async([]{ return fibonacci<cpp_int>(2'000'000); }); auto z = when_all(std::move(x), std::move(y)).then([](auto f){ auto t = f.get(); return cpp_int(get<0>(t).get() * get<1>(t).get()); }); cout << z.get() << endl; 45 f is a future tuple of futures result is 626,964 digits
  • 87. © 2014 Adobe Systems Incorporated. All Rights Reserved. Futures 46
  • 88. © 2013 Adobe Systems Incorporated. All Rights Reserved. Futures: Continuations future<cpp_int> x = async([]{ return fibonacci<cpp_int>(100); }); future<cpp_int> y = x.then([](future<cpp_int> x){ return cpp_int(x.get() * 2); }); future<cpp_int> z = x.then([](future<cpp_int> x){ return cpp_int(x.get() / 15); }); 47
  • 89. © 2013 Adobe Systems Incorporated. All Rights Reserved. Futures: Continuations future<cpp_int> x = async([]{ return fibonacci<cpp_int>(100); }); future<cpp_int> y = x.then([](future<cpp_int> x){ return cpp_int(x.get() * 2); }); future<cpp_int> z = x.then([](future<cpp_int> x){ return cpp_int(x.get() / 15); }); 47 Assertion failed: (px != 0), function operator->, file shared_ptr.hpp, line 648.
  • 90. © 2014 Adobe Systems Incorporated. All Rights Reserved. Continuations ! Desired behavior ! A future should behave as a regular type - a token for the actual value ! shared_futures let me pass them around and do multiple get() operations, but don’t fix continuations ! [at least with boost] ! Releasing the last instance of a future should cancel (no-op) any unexecuted, contributing, operations 48
  • 91. © 2014 Adobe Systems Incorporated. All Rights Reserved. Futures 49
  • 92. © 2014 Adobe Systems Incorporated. All Rights Reserved. Futures 49 shared
  • 93. © 2014 Adobe Systems Incorporated. All Rights Reserved. Futures 50
  • 94. © 2014 Adobe Systems Incorporated. All Rights Reserved. Futures 50 shared shared shared
  • 95. © 2013 Adobe Systems Incorporated. All Rights Reserved. Futures: Building, The template <typename> struct result_of_; //not defined template <typename R, typename... Args> struct result_of_<R(Args...)> { using type = R; }; template <typename F> using result_of_t_ = typename result_of_<F>::type; 51
  • 96. © 2013 Adobe Systems Incorporated. All Rights Reserved. Futures: Building, The template <typename> struct result_of_; //not defined template <typename R, typename... Args> struct result_of_<R(Args...)> { using type = R; }; template <typename F> using result_of_t_ = typename result_of_<F>::type; 51 result_of_t_<int(double)> -> int
  • 97. © 2013 Adobe Systems Incorporated. All Rights Reserved. Futures: Building, The template <typename> class packaged_task; //not defined template <typename R> class future { shared_ptr</* ... */> _p; public: future() = default; template <typename F> auto then(F&& f) { } const R& get() const { } }; template<typename R, typename ...Args > class packaged_task<R (Args...)> { weak_ptr</* ... */> _p; public: packaged_task() = default; template <typename... A> void operator()(A&&... args) const { } }; 52
  • 98. © 2013 Adobe Systems Incorporated. All Rights Reserved. Futures: Building, The template <typename> class packaged_task; //not defined template <typename R> class future { shared_ptr</* ... */> _p; public: future() = default; template <typename F> auto then(F&& f) { } const R& get() const { } }; template<typename R, typename ...Args > class packaged_task<R (Args...)> { weak_ptr</* ... */> _p; public: packaged_task() = default; template <typename... A> void operator()(A&&... args) const { } }; 52
  • 99. © 2013 Adobe Systems Incorporated. All Rights Reserved. Futures: Building, The template <typename> class packaged_task; //not defined template <typename R> class future { shared_ptr</* ... */> _p; public: future() = default; template <typename F> auto then(F&& f) { } const R& get() const { } }; template<typename R, typename ...Args > class packaged_task<R (Args...)> { weak_ptr</* ... */> _p; public: packaged_task() = default; template <typename... A> void operator()(A&&... args) const { } }; 52
  • 100. © 2013 Adobe Systems Incorporated. All Rights Reserved. Futures: Building, The template <typename> class packaged_task; //not defined template <typename R> class future { shared_ptr</* ... */> _p; public: future() = default; template <typename F> auto then(F&& f) { } const R& get() const { } }; template<typename R, typename ...Args > class packaged_task<R (Args...)> { weak_ptr</* ... */> _p; public: packaged_task() = default; template <typename... A> void operator()(A&&... args) const { } }; 52
  • 101. © 2013 Adobe Systems Incorporated. All Rights Reserved. Futures: Building, The template <typename> class packaged_task; //not defined template <typename R> class future { shared_ptr</* ... */> _p; public: future() = default; template <typename F> auto then(F&& f) { } const R& get() const { } }; template<typename R, typename ...Args > class packaged_task<R (Args...)> { weak_ptr</* ... */> _p; public: packaged_task() = default; template <typename... A> void operator()(A&&... args) const { } }; 52
  • 102. © 2013 Adobe Systems Incorporated. All Rights Reserved. template <typename> class packaged_task; //not defined template <typename> class future; template <typename S, typename F> auto package(F&& f) -> pair<packaged_task<S>, future<result_of_t_<S>>>; template <typename R> class future { shared_ptr</* ... */> _p; template <typename S, typename F> friend auto package(F&& f) -> pair<packaged_task<S>, future<result_of_t_<S>>>; explicit future(shared_ptr</* ... */> p) : _p(move(p)) { } /* ... */ }; template<typename R, typename ...Args > class packaged_task<R (Args...)> { weak_ptr</* ... */> _p; template <typename S, typename F> friend auto package(F&& f) -> pair<packaged_task<S>, future<result_of_t_<S>>>; explicit packaged_task(weak_ptr</* ... */> p) : _p(move(p)) { } /* ... */ }; Futures: Building, The 53
  • 103. © 2013 Adobe Systems Incorporated. All Rights Reserved. template <typename> class packaged_task; //not defined template <typename> class future; template <typename S, typename F> auto package(F&& f) -> pair<packaged_task<S>, future<result_of_t_<S>>>; template <typename R> class future { shared_ptr</* ... */> _p; template <typename S, typename F> friend auto package(F&& f) -> pair<packaged_task<S>, future<result_of_t_<S>>>; explicit future(shared_ptr</* ... */> p) : _p(move(p)) { } /* ... */ }; template<typename R, typename ...Args > class packaged_task<R (Args...)> { weak_ptr</* ... */> _p; template <typename S, typename F> friend auto package(F&& f) -> pair<packaged_task<S>, future<result_of_t_<S>>>; explicit packaged_task(weak_ptr</* ... */> p) : _p(move(p)) { } /* ... */ }; Futures: Building, The 53
  • 104. © 2013 Adobe Systems Incorporated. All Rights Reserved. template <typename> class packaged_task; //not defined template <typename> class future; template <typename S, typename F> auto package(F&& f) -> pair<packaged_task<S>, future<result_of_t_<S>>>; template <typename R> class future { shared_ptr</* ... */> _p; template <typename S, typename F> friend auto package(F&& f) -> pair<packaged_task<S>, future<result_of_t_<S>>>; explicit future(shared_ptr</* ... */> p) : _p(move(p)) { } /* ... */ }; template<typename R, typename ...Args > class packaged_task<R (Args...)> { weak_ptr</* ... */> _p; template <typename S, typename F> friend auto package(F&& f) -> pair<packaged_task<S>, future<result_of_t_<S>>>; explicit packaged_task(weak_ptr</* ... */> p) : _p(move(p)) { } /* ... */ }; Futures: Building, The 53
  • 105. © 2013 Adobe Systems Incorporated. All Rights Reserved. template <typename> class packaged_task; //not defined template <typename> class future; template <typename S, typename F> auto package(F&& f) -> pair<packaged_task<S>, future<result_of_t_<S>>>; template <typename R> class future { shared_ptr</* ... */> _p; template <typename S, typename F> friend auto package(F&& f) -> pair<packaged_task<S>, future<result_of_t_<S>>>; explicit future(shared_ptr</* ... */> p) : _p(move(p)) { } /* ... */ }; template<typename R, typename ...Args > class packaged_task<R (Args...)> { weak_ptr</* ... */> _p; template <typename S, typename F> friend auto package(F&& f) -> pair<packaged_task<S>, future<result_of_t_<S>>>; explicit packaged_task(weak_ptr</* ... */> p) : _p(move(p)) { } /* ... */ }; Futures: Building, The 53
  • 106. © 2013 Adobe Systems Incorporated. All Rights Reserved. template <typename S, typename F> auto package(F&& f) -> pair<packaged_task<S>, future<result_of_t_<S>>> { auto p = make_shared<shared<S>>(forward<F>(f)); return make_pair(packaged_task<S>(p), future<result_of_t_<S>>(p)); } Futures: Building, The 54
  • 107. © 2013 Adobe Systems Incorporated. All Rights Reserved. template <typename S, typename F> auto package(F&& f) -> pair<packaged_task<S>, future<result_of_t_<S>>> { auto p = make_shared<shared<S>>(forward<F>(f)); return make_pair(packaged_task<S>(p), future<result_of_t_<S>>(p)); } Futures: Building, The 54 package<int(double)>(f) -> { void(double), future<int> }
  • 108. © 2013 Adobe Systems Incorporated. All Rights Reserved. template <typename R> struct shared_base { vector<R> _r; // optional mutex _mutex; condition_variable _ready; vector<function<void()>> _then; virtual ~shared_base() { } /* ... */ }; template <typename> struct shared; // not defined template <typename R, typename... Args> struct shared<R(Args...)> : shared_base<R> { function<R(Args...)> _f; template<typename F> shared(F&& f) : _f(forward<F>(f)) { } /* ... */ }; Futures: Building, The 55
  • 109. © 2013 Adobe Systems Incorporated. All Rights Reserved. template <typename R> struct shared_base { vector<R> _r; // optional mutex _mutex; condition_variable _ready; vector<function<void()>> _then; virtual ~shared_base() { } /* ... */ }; template <typename> struct shared; // not defined template <typename R, typename... Args> struct shared<R(Args...)> : shared_base<R> { function<R(Args...)> _f; template<typename F> shared(F&& f) : _f(forward<F>(f)) { } /* ... */ }; Futures: Building, The 55
  • 110. © 2013 Adobe Systems Incorporated. All Rights Reserved. template <typename R> struct shared_base { vector<R> _r; // optional mutex _mutex; condition_variable _ready; vector<function<void()>> _then; virtual ~shared_base() { } /* ... */ }; template <typename> struct shared; // not defined template <typename R, typename... Args> struct shared<R(Args...)> : shared_base<R> { function<R(Args...)> _f; template<typename F> shared(F&& f) : _f(forward<F>(f)) { } /* ... */ }; Futures: Building, The 55
  • 111. © 2013 Adobe Systems Incorporated. All Rights Reserved. template<typename R, typename ...Args > class packaged_task<R (Args...)> { weak_ptr<shared<R(Args...)>> _p; template <typename S, typename F> friend auto package(F&& f) -> pair<packaged_task<S>, future<result_of_t_<S>>>; explicit packaged_task(weak_ptr<shared<R(Args...)>> p) : _p(move(p)) { } public: packaged_task() = default; template <typename... A> void operator()(A&&... args) const { auto p = _p.lock(); if (p) (*p)(forward<A>(args)...); } }; Futures: Building, The 56
  • 112. © 2013 Adobe Systems Incorporated. All Rights Reserved. template<typename R, typename ...Args > class packaged_task<R (Args...)> { weak_ptr<shared<R(Args...)>> _p; template <typename S, typename F> friend auto package(F&& f) -> pair<packaged_task<S>, future<result_of_t_<S>>>; explicit packaged_task(weak_ptr<shared<R(Args...)>> p) : _p(move(p)) { } public: packaged_task() = default; template <typename... A> void operator()(A&&... args) const { auto p = _p.lock(); if (p) (*p)(forward<A>(args)...); } }; Futures: Building, The 56
  • 113. © 2013 Adobe Systems Incorporated. All Rights Reserved. template<typename R, typename ...Args > class packaged_task<R (Args...)> { weak_ptr<shared<R(Args...)>> _p; template <typename S, typename F> friend auto package(F&& f) -> pair<packaged_task<S>, future<result_of_t_<S>>>; explicit packaged_task(weak_ptr<shared<R(Args...)>> p) : _p(move(p)) { } public: packaged_task() = default; template <typename... A> void operator()(A&&... args) const { auto p = _p.lock(); if (p) (*p)(forward<A>(args)...); } }; Futures: Building, The 56
  • 114. © 2013 Adobe Systems Incorporated. All Rights Reserved. template <typename R, typename... Args> struct shared<R(Args...)> : shared_base<R> { function<R(Args...)> _f; template<typename F> shared(F&& f) : _f(forward<F>(f)) { } template <typename... A> void operator()(A&&... args) { this->set(_f(forward<A>(args)...)); _f = nullptr; } }; Futures: Building, The 57
  • 115. © 2013 Adobe Systems Incorporated. All Rights Reserved. template <typename R, typename... Args> struct shared<R(Args...)> : shared_base<R> { function<R(Args...)> _f; template<typename F> shared(F&& f) : _f(forward<F>(f)) { } template <typename... A> void operator()(A&&... args) { this->set(_f(forward<A>(args)...)); _f = nullptr; } }; Futures: Building, The 57
  • 116. © 2013 Adobe Systems Incorporated. All Rights Reserved. template <typename R> struct shared_base { vector<R> _r; // optional mutex _mutex; condition_variable _ready; vector<function<void()>> _then; virtual ~shared_base() { } void set(R&& r) { vector<function<void()>> then; { lock_t lock{_mutex}; _r.push_back(move(r)); swap(_then, then); } _ready.notify_all(); for (const auto& f : then) _system.async_(move(f)); } }; Futures: Building, The 58
  • 117. © 2013 Adobe Systems Incorporated. All Rights Reserved. template <typename R> struct shared_base { vector<R> _r; // optional mutex _mutex; condition_variable _ready; vector<function<void()>> _then; virtual ~shared_base() { } void set(R&& r) { vector<function<void()>> then; { lock_t lock{_mutex}; _r.push_back(move(r)); swap(_then, then); } _ready.notify_all(); for (const auto& f : then) _system.async_(move(f)); } }; Futures: Building, The 58
  • 118. © 2013 Adobe Systems Incorporated. All Rights Reserved. template <typename R> class future { shared_ptr<shared_base<R>> _p; template <typename S, typename F> friend auto package(F&& f) -> pair<packaged_task<S>, future<result_of_t_<S>>>; explicit future(shared_ptr<shared_base<R>> p) : _p(move(p)) { } public: future() = default; template <typename F> auto then(F&& f) { auto pack = package<result_of_t<F(R)>()>([p = _p, f = forward<F>(f)](){ return f(p->_r.back()); }); _p->then(move(pack.first)); return pack.second; } const R& get() const { return _p->get(); } }; Futures: Building, The 59
  • 119. © 2013 Adobe Systems Incorporated. All Rights Reserved. template <typename R> class future { shared_ptr<shared_base<R>> _p; template <typename S, typename F> friend auto package(F&& f) -> pair<packaged_task<S>, future<result_of_t_<S>>>; explicit future(shared_ptr<shared_base<R>> p) : _p(move(p)) { } public: future() = default; template <typename F> auto then(F&& f) { auto pack = package<result_of_t<F(R)>()>([p = _p, f = forward<F>(f)](){ return f(p->_r.back()); }); _p->then(move(pack.first)); return pack.second; } const R& get() const { return _p->get(); } }; Futures: Building, The 59
  • 120. © 2013 Adobe Systems Incorporated. All Rights Reserved. template <typename R> class future { shared_ptr<shared_base<R>> _p; template <typename S, typename F> friend auto package(F&& f) -> pair<packaged_task<S>, future<result_of_t_<S>>>; explicit future(shared_ptr<shared_base<R>> p) : _p(move(p)) { } public: future() = default; template <typename F> auto then(F&& f) { auto pack = package<result_of_t<F(R)>()>([p = _p, f = forward<F>(f)](){ return f(p->_r.back()); }); _p->then(move(pack.first)); return pack.second; } const R& get() const { return _p->get(); } }; Futures: Building, The 59
  • 121. © 2013 Adobe Systems Incorporated. All Rights Reserved. template <typename R> class future { shared_ptr<shared_base<R>> _p; template <typename S, typename F> friend auto package(F&& f) -> pair<packaged_task<S>, future<result_of_t_<S>>>; explicit future(shared_ptr<shared_base<R>> p) : _p(move(p)) { } public: future() = default; template <typename F> auto then(F&& f) { auto pack = package<result_of_t<F(R)>()>([p = _p, f = forward<F>(f)](){ return f(p->_r.back()); }); _p->then(move(pack.first)); return pack.second; } const R& get() const { return _p->get(); } }; Futures: Building, The 59
  • 122. © 2013 Adobe Systems Incorporated. All Rights Reserved. template <typename R> struct shared_base { vector<R> _r; // optional mutex _mutex; condition_variable _ready; vector<function<void()>> _then; virtual ~shared_base() { } void set(R&& r) { } template <typename F> void then(F&& f) { bool resolved{false}; { lock_t lock{_mutex}; if (_r.empty()) _then.push_back(forward<F>(f)); else resolved = true; } if (resolved) _system.async_(move(f)); } const R& get() { lock_t lock{_mutex}; while (_r.empty()) _ready.wait(lock); return _r.back(); } }; Futures: Building, The 60
  • 123. © 2013 Adobe Systems Incorporated. All Rights Reserved. template <typename R> struct shared_base { vector<R> _r; // optional mutex _mutex; condition_variable _ready; vector<function<void()>> _then; virtual ~shared_base() { } void set(R&& r) { } template <typename F> void then(F&& f) { bool resolved{false}; { lock_t lock{_mutex}; if (_r.empty()) _then.push_back(forward<F>(f)); else resolved = true; } if (resolved) _system.async_(move(f)); } const R& get() { lock_t lock{_mutex}; while (_r.empty()) _ready.wait(lock); return _r.back(); } }; Futures: Building, The 60
  • 124. © 2013 Adobe Systems Incorporated. All Rights Reserved. template <typename R> struct shared_base { vector<R> _r; // optional mutex _mutex; condition_variable _ready; vector<function<void()>> _then; virtual ~shared_base() { } void set(R&& r) { } template <typename F> void then(F&& f) { bool resolved{false}; { lock_t lock{_mutex}; if (_r.empty()) _then.push_back(forward<F>(f)); else resolved = true; } if (resolved) _system.async_(move(f)); } const R& get() { lock_t lock{_mutex}; while (_r.empty()) _ready.wait(lock); return _r.back(); } }; Futures: Building, The 60
  • 125. © 2014 Adobe Systems Incorporated. All Rights Reserved. Futures 61
  • 126. © 2014 Adobe Systems Incorporated. All Rights Reserved. Futures 61 shared shared shared
  • 127. © 2013 Adobe Systems Incorporated. All Rights Reserved. template <typename F, typename ...Args> auto async(F&& f, Args&&... args) { using result_type = result_of_t<F (Args...)>; using packaged_type = packaged_task<result_type()>; auto pack = package<result_type()>(bind(forward<F>(f), forward<Args>(args)...)); _system.async_(move(get<0>(pack))); return get<1>(pack); } Futures: Building, The 62
  • 128. © 2013 Adobe Systems Incorporated. All Rights Reserved. Futures: Continuations future<cpp_int> x = async([]{ return fibonacci<cpp_int>(100); }); future<cpp_int> y = x.then([](const cpp_int& x){ return cpp_int(x * 2); }); future<cpp_int> z = x.then([](const cpp_int& x){ return cpp_int(x / 15); }); cout << y.get() << endl; cout << z.get() << endl; 63
  • 129. © 2013 Adobe Systems Incorporated. All Rights Reserved. Futures: Continuations future<cpp_int> x = async([]{ return fibonacci<cpp_int>(100); }); future<cpp_int> y = x.then([](const cpp_int& x){ return cpp_int(x * 2); }); future<cpp_int> z = x.then([](const cpp_int& x){ return cpp_int(x / 15); }); cout << y.get() << endl; cout << z.get() << endl; 63 708449696358523830150 23614989878617461005
  • 130. © 2014 Adobe Systems Incorporated. All Rights Reserved. Property Models 64
  • 131. © 2013 Adobe Systems Incorporated. All Rights Reserved. What if we persist the graph? 65
  • 132. © 2013 Adobe Systems Incorporated. All Rights Reserved. What if we persist the graph? ! Allow multiple invocations of the tasks by setting the source values ! Each change triggers a notification to the sink values ! This is a reactive programming model and futures are known as behaviors 66
  • 133. © 2013 Adobe Systems Incorporated. All Rights Reserved. How do the graphs change during execution? 67
  • 134. © 2013 Adobe Systems Incorporated. All Rights Reserved. Property Model 68 a c R{a,b,c} b
  • 135. © 2013 Adobe Systems Incorporated. All Rights Reserved. A function is a directed relationship ! We can remove the arrows by providing a package of functions to represent the relationship ! a = b * c
 b = a / c
 c = a / b ! This forms a type of constraint system called a property model ! Flow is determined by value, or cell, priority ! Cells can only have one in-edge for a given flow or the system is over constrained 69
  • 136. © 2013 Adobe Systems Incorporated. All Rights Reserved. Property Model 70 sink source source sink
  • 137. © 2013 Adobe Systems Incorporated. All Rights Reserved. Property Models ! Reflowing a property model doesn’t require all relationships to be resolved ! The task representing them can still be executing concurrently ! This creates a single dependency graph that is appended to for each new flow and is pruned and unravels as tasks are complete 71
  • 138. © 2013 Adobe Systems Incorporated. All Rights Reserved. Property Model 72 source source sink sink source sink sink
  • 139. © 2013 Adobe Systems Incorporated. All Rights Reserved. Final Thoughts ! Perhaps representing such systems as if it where imperative code is not the correct approach ! Instead the a graph description can be compiled and statically validated 73
  • 140. © 2014 Adobe Systems Incorporated. All Rights Reserved.