SlideShare a Scribd company logo
1 of 95
C++ Coroutines
a negative overhead abstraction
gorn@microsoft.com
What this talk is about?
• C++ Coroutines
• Lightweight, customizable coroutines
• C++17 (maybe)
• Experimental Implementation in
MSVC 2015, Clang in progress, EDG
2012 - N3328
2013 - N3564
2013 - N3650
2013 - N3722
2014 - N3858
2014 - N3977
2014 - N4134 EWG direction
approved
2014 - N4286
2015 - N4403 EWG accepted,
sent to Core WG
2015 - P0057R0 Core & LEWG review (co_xxx)
2016 - P0057R2 more Core & LEWG review
C++ Russia 2016 Coroutines 2
C++ in two lines
• Direct mapping to hardware
• Zero-overhead abstractions
C++ Russia 2016 Coroutines 3
From Bjarne Stroustrup lecture:
The Essence of C++
Assembler BCPL C
Simula
C++
General-Purpose Abstractions
C++11 C++14
Direct Mapping to hardware
C++ Russia 2016 Coroutines 4
C++ Russia 2016 Coroutines 5
000100 IDENTIFICATION DIVISION.
000200 PROGRAM-ID. HELLOWORLD.
000300*
000400 ENVIRONMENT DIVISION.
000500 CONFIGURATION SECTION.
000600 SOURCE-COMPUTER. RM-COBOL.
000700 OBJECT-COMPUTER. RM-COBOL.
000800
001000 DATA DIVISION.
001100 FILE SECTION.
001200
100000 PROCEDURE DIVISION.
100100
100200 MAIN-LOGIC SECTION.
100300 BEGIN.
100400 DISPLAY " " LINE 1 POSITION 1 ERASE EOS.
100500 DISPLAY "Hello world!" LINE 15 POSITION 10.
100600 STOP RUN.
100700 MAIN-LOGIC-EXIT.
100800 EXIT.
C++ Russia 2016 Coroutines 6
C++ Russia 2016 Coroutines 7
C++ Russia 2016 Coroutines 8
C++ Russia 2016 Coroutines 9

Joel Erdwinn
Melvin Conway
C++ Russia 2016 Coroutines 10
image credits: wikipedia commons, Communication of the ACM vol.6 No.7 July 1963
C
S
Y
A
A
C Y
Write to
Tape
S A1
C Y2
Subroutine Coroutine
Basic Symbol
Reducer
A
C
Basic Name
Reducer
A
C
S AS Y
output token
S A
Basic Symbol
Reducer
S Y
S
Y
S A
C Y
1
2
S Y3
S A
read token
read token
Subroutine
Subroutine
Subroutine
SubroutineCoroutine
C++ Russia 2016 Coroutines 11
100 cards per minute!
C++ Russia 2016 Coroutines 12
C++ Russia 2016 Coroutines 13
Async state machine
C++ Russia 2016 Coroutines 14
Failed
Connecting
Completed
Reading
Trivial if synchronous
int tcp_reader(int total)
{
char buf[4 * 1024];
auto conn = Tcp::Connect("127.0.0.1", 1337);
for (;;)
{
auto bytesRead = conn.Read(buf, sizeof(buf));
total -= bytesRead;
if (total <= 0 || bytesRead == 0) return total;
}
}
C++ Russia 2016 Coroutines 15
std::future<T> and std::promise<T>
shared_state<T>
atomic<long> refCnt;
mutex lock;
variant<empty, T, exception_ptr> value;
conditional_variable ready;
future<T>
intrusive_ptr<shared_state<T>>
wait()
T get()
promise<T>
intrusive_ptr<shared_state<T>>
set_value(T)
set_exception(exception_ptr)
C++ Russia 2016 Coroutines 16
future<int> tcp_reader(int64_t total) {
struct State {
char buf[4 * 1024];
int64_t total;
Tcp::Connection conn;
explicit State(int64_t total) : total(total) {}
};
auto state = make_shared<State>(total);
return Tcp::Connect("127.0.0.1", 1337).then(
[state](future<Tcp::Connection> conn) {
state->conn = std::move(conn.get());
return do_while([state]()->future<bool> {
if (state->total <= 0) return make_ready_future(false);
return state->conn.read(state->buf, sizeof(state->buf)).then(
[state](future<int> nBytesFut) {
auto nBytes = nBytesFut.get()
if (nBytes == 0) return make_ready_future(false);
state->total -= nBytes;
return make_ready_future(true);
});
});
});
}
N4399 Working Draft,
Technical Specification for C++
Extensions for Concurrency
.then
future<void> do_while(function<future<bool>()> body) {
return body().then([=](future<bool> notDone) {
return notDone.get() ? do_while(body) : make_ready_future(); });
} C++ Russia 2016 Coroutines 17
Forgot something
int tcp_reader(int total)
{
char buf[4 * 1024];
auto conn = Tcp::Connect("127.0.0.1", 1337);
for (;;)
{
auto bytesRead = conn.Read(buf, sizeof(buf));
total -= bytesRead;
if (total <= 0 || bytesRead == 0) return total;
}
}
C++ Russia 2016 Coroutines 18
future<int> tcp_reader(int64_t total) {
struct State {
char buf[4 * 1024];
int64_t total;
Tcp::Connection conn;
explicit State(int64_t total) : total(total) {}
};
auto state = make_shared<State>(total);
return Tcp::Connect("127.0.0.1", 1337).then(
[state](future<Tcp::Connection> conn) {
state->conn = std::move(conn.get());
return do_while([state]()->future<bool> {
if (state->total <= 0) return make_ready_future(false);
return state->conn.read(state->buf, sizeof(state->buf)).then(
[state](future<int> nBytesFut) {
auto nBytes = nBytesFut.get()
if (nBytes == 0) return make_ready_future(false);
state->total -= nBytes;
return make_ready_future(true);
}); // read
}); // do_while
}); // Tcp::Connect
}
.then
C++ Russia 2016 Coroutines 19
future<int> tcp_reader(int64_t total) {
struct State {
char buf[4 * 1024];
int64_t total;
Tcp::Connection conn;
explicit State(int64_t total) : total(total) {}
};
auto state = make_shared<State>(total);
return Tcp::Connect("127.0.0.1", 1337).then(
[state](future<Tcp::Connection> conn) {
state->conn = std::move(conn.get());
return do_while([state]()->future<bool> {
if (state->total <= 0) return make_ready_future(false);
return state->conn.read(state->buf, sizeof(state->buf)).then(
[state](future<int> nBytesFut) {
auto nBytes = nBytesFut.get()
if (nBytes == 0) return make_ready_future(false);
state->total -= nBytes;
return make_ready_future(true);
}); // read
}); // do_while
}).then([state](future<void>){return make_ready_future(state->total)});
}
.then
C++ Russia 2016 Coroutines 20
C++ Russia 2016 Coroutines 21
Hand-crafted async state machine (1/3)
class tcp_reader
{
char buf[64 * 1024];
Tcp::Connection conn;
promise<int> done;
int total;
explicit tcp_reader(int total): total(total) {}
void OnConnect(error_code ec, Tcp::Connection newCon);
void OnRead(error_code ec, int bytesRead);
void OnError(error_code ec);
void OnComplete();
public:
static future<int> start(int total);
};
int main() {
cout << tcp_reader::start(1000 * 1000 * 1000).get(); }
Failed
Connecting
Completed
Reading
①
①
②
②
③
③
④
④
⑤
⑤
Hand-crafted async state machine (2/3)
C++ Russia 2016 Coroutines 22
future<int> tcp_reader::start(int total) {
auto p = make_unique<tcp_reader>(total);
auto result = p->done.get_future();
Tcp::Connect("127.0.0.1", 1337,
[raw = p.get()](auto ec, auto newConn) {
raw->OnConnect(ec, std::move(newConn));
});
p.release();
return result;
}
void tcp_reader::OnConnect(error_code ec,
Tcp::Connection newCon)
{
if (ec) return OnError(ec);
conn = std::move(newCon);
conn.Read(buf, sizeof(buf),
[this](error_code ec, int bytesRead)
{ OnRead(ec, bytesRead); });
}
Hand-crafted async state machine (3/3)
C++ Russia 2016 Coroutines 23
void tcp_reader::OnRead(error_code ec, int bytesRead) {
if (ec) return OnError(ec);
total -= bytesRead;
if (total <= 0 || bytesRead == 0) return OnComplete();
conn.Read(buf, sizeof(buf),
[this](error_code ec, int bytesRead) {
OnRead(ec, bytesRead); });
}
void OnError(error_code ec) {
auto cleanMe = unique_ptr<tcp_reader>(this);
done.set_exception(make_exception_ptr(system_error(ec)));
}
void OnComplete() {
auto cleanMe = unique_ptr<tcp_reader>(this);
done.set_value(total);
}
Async state machine
C++ Russia 2016 Coroutines 24
Failed
Connecting
Completed
Reading
Trivial
auto tcp_reader(int total) -> int
{
char buf[4 * 1024];
auto conn = Tcp::Connect("127.0.0.1", 1337);
for (;;)
{
auto bytesRead = conn.Read(buf, sizeof(buf));
total -= bytesRead;
if (total <= 0 || bytesRead == 0) return total;
}
}
C++ Russia 2016 Coroutines 25
Trivial
auto tcp_reader(int total) -> future<int>
{
char buf[4 * 1024];
auto conn = await Tcp::Connect("127.0.0.1", 1337);
for (;;)
{
auto bytesRead = await conn.Read(buf, sizeof(buf));
total -= bytesRead;
if (total <= 0 || bytesRead == 0) return total;
}
}
C++ Russia 2016 Coroutines 26
What about perf?
MB/s
Binary size
(Kbytes)
Visual C++ 2015 RTM. Measured on Lenovo W540 laptop. Transmitting & Receiving 1GB over loopback IP addr
C++ Russia 2016 Coroutines 27
495 (1.3x) 380 0
25 (0.85x) 30 9
Hand-CraftedCoroutines
int main() {
printf("Hello, worldn");
}
Hello
Coroutines are closer to the metal
C++ Russia 2016 Coroutines 28
Hardware
OS / Low Level Libraries
Handcrafted
State
Machines
I/O Abstractions
(Callback based) I/O Abstraction
(Awaitable based)
Coroutines
How to map high level call to OS API?
C++ Russia 2016 Coroutines 29
template <class Cb>
void Read(void* buf, size_t bytes, Cb && cb);
conn.Read(buf, sizeof(buf),
[this](error_code ec, int bytesRead)
{ OnRead(ec, bytesRead); });
Windows: WSARecv(fd, ..., OVERLAPPED*) Posix aio: aio_read(fd, ..., aiocbp*)
aiocbp
Function
Object
OVERLAPPED
Function
Object
struct OverlappedBase : os_async_context {
virtual void Invoke(std::error_code, int bytes) = 0;
virtual ~OverlappedBase() {}
static void io_complete_callback(CompletionPacket& p) {
auto me = unique_ptr<OverlappedBase>(static_cast<OverlappedBase*>(p.overlapped));
me->Invoke(p.error, p.byteTransferred);
}
};
template <typename Fn> unique_ptr<OverlappedBase> make_handler_with_count(Fn && fn) {
return std::make_unique<CompletionWithCount<std::decay_t<Fn>>(std::forward<Fn>(fn));
}
os_async_ctx
OVERLAPPED/aiocbp
Function
Object
After open associate a socket handle with a threadpool and a callback
ThreadPool::AssociateHandle(sock.native_handle(), &OverlappedBase::io_complete_callback);
template <typename Fn> struct CompletionWithCount : OverlappedBase, private Fn
{
CompletionWithCount(Fn fn) : Fn(std::move(fn)) {}
void Invoke(std::error_code ec, int count) override { Fn::operator()(ec, count); }
};
C++ Russia 2016 Coroutines 30
template <typename F>
void Read(void* buf, int len, F && cb) {
return Read(buf, len, make_handler_with_count(std::forward<F>(cb)));
}
void Read(void* buf, int len, std::unique_ptr<detail::OverlappedBase> o)
{
auto error = sock.Receive(buf, len, o.get());
if (error) {
if (error.value() != kIoPending) {
o->Invoke(error, 0);
return;
}
}
o.release();
}
conn.Read(buf, sizeof(buf),
[this](error_code ec, int bytesRead)
{ OnRead(ec, bytesRead); });
C++ Russia 2016 Coroutines 31
await conn.Read(buf, sizeof(buf));
?
C++ Russia 2016 Coroutines 32
Awaitable – Concept of the Future<T>
C++ Russia 2016 Coroutines 33
.await_ready()
F<T> → bool
.await_suspend(cb)
F<T> x Fn → void
.await_resume()
F<T> → T
Present
T
Present
T
Present
T
await expr-of-awaitable-type
await <expr>
C++ Russia 2016 Coroutines
Expands into an expression equivalent of
{
auto && tmp = operator await(opt) <expr>;
if (!tmp.await_ready()) {
tmp.await_suspend(<coroutine-handle>);
}
return tmp.await_resume(tmp);
}
suspend
resume
34
Overlapped Base from before
struct OverlappedBase : os_async_context
{
virtual void Invoke(std::error_code, int bytes) = 0;
virtual ~OverlappedBase() {}
static void io_complete_callback(CompletionPacket& p) {
auto me = static_cast<OverlappedBase*>(p.overlapped);
auto cleanMe = unique_ptr<OverlappedBase>(me);
me->Invoke(p.error, p.byteTransferred);
}
};
C++ Russia 2016 Coroutines 35
Overlapped Base for awaitable
struct AwaiterBase : os_async_context
{
coroutine_handle<> resume;
std::error_code err;
int bytes;
static void io_complete_callback(CompletionPacket& p) {
auto me = static_cast<AwaiterBase*>(p.overlapped);
me->err = p.error;
me->bytes = p.byteTransferred;
me->resume();
}
};
mov rcx, [rcx]
jmp [rcx]
sizeof(void*)
no dtor
C++ Russia 2016 Coroutines 36
await conn.Read(buf, sizeof(buf));
?
C++ Russia 2016 Coroutines 37
auto Connection::Read(void* buf, int len) {
struct awaiter: AwaiterBase {
Connection* me;
void* buf;
awaiter(Connection* me, void* buf, int len) : me(me), buf(buf) { bytes = len; }
bool await_ready() { return false; }
void await_suspend(coroutine_handle<> h) {
this->resume = h;
auto error = me->sock.Receive(buf, bytes, this);
if (error.value() != kIoPending)
throw system_error(err);
}
int await_resume() {
if (this->err) throw system_error(err);
return bytes;
}
};
return awaiter{ this, buf, len };
}
C++ Russia 2016 Coroutines 38
struct AwaiterBase : os_async_context {
coroutine_handle<> resume;
std::error_code err;
int bytes;
static void io_complete_callback(CompletionPacket& p){
auto me = static_cast<AwaiterBase*>(p.overlapped);
me->err = p.error;
me->bytes = p.byteTransferred;
me->resume();
}
};
Trivial
auto tcp_reader(int total) -> future<int>
{
char buf[4 * 1024];
auto conn = await Tcp::Connect("127.0.0.1", 1337);
for (;;)
{
auto bytesRead = await conn.Read(buf, sizeof(buf));
total -= bytesRead;
if (total <= 0 || bytesRead == 0) return total;
}
}
C++ Russia 2016 Coroutines 39
Can we make it better?
50% I/O completes synchronously
50% I/O with I/O pending error
C++ Russia 2016 Coroutines 40
SetFileCompletionNotificationModes(h,
FILE_SKIP_COMPLETION_PORT_ON_SUCCESS);
Take advantage of synchronous completions
C++ Russia 2016 Coroutines 41
void Read(void* buf, int len, std::unique_ptr<detail::OverlappedBase> o)
{
auto error = sock.Receive(buf, len, o.get());
if (error) {
if (error.value() != kIoPending) {
o->Invoke(error, 0);
return;
}
}
o.release();
}
SetFileCompletionNotificationModes(h,
FILE_SKIP_COMPLETION_PORT_ON_SUCCESS);
Take advantage of synchronous completions
C++ Russia 2016 Coroutines 42
void Read(void* buf, int len, std::unique_ptr<detail::OverlappedBase> o)
{
auto error = sock.Receive(buf, len, o.get());
if (error.value() != kIoPending) {
o->Invoke(error, len);
return;
}
o.release();
}
SetFileCompletionNotificationModes(h,
FILE_SKIP_COMPLETION_PORT_ON_SUCCESS);
Take advantage of synchronous completions
C++ Russia 2016 Coroutines 43
void Read(void* buf, int len, std::unique_ptr<detail::OverlappedBase> o)
{
auto error = sock.Receive(buf, len, o.get());
if (error.value() != kIoPending) {
o->Invoke(error, len);
return;
}
o.release();
}
SetFileCompletionNotificationModes(h,
FILE_SKIP_COMPLETION_PORT_ON_SUCCESS);
SuperLean.exe!improved::tcp_reader::OnRead(std::error_code ec, int bytesRead) Line 254
SuperLean.exe!improved::detail::CompletionWithSizeT<<lambda_ee38b7a750c7f550b4ee1dd60c2450c1> >::Invoke(std::error_code ec, int count) Line 31
SuperLean.exe!improved::tcp_reader::OnRead(std::error_code ec, int bytesRead) Line 254
SuperLean.exe!improved::detail::CompletionWithSizeT<<lambda_ee38b7a750c7f550b4ee1dd60c2450c1> >::Invoke(std::error_code ec, int count) Line 31
SuperLean.exe!improved::tcp_reader::OnRead(std::error_code ec, int bytesRead) Line 254
SuperLean.exe!improved::detail::CompletionWithSizeT<<lambda_ee38b7a750c7f550b4ee1dd60c2450c1> >::Invoke(std::error_code ec, int count) Line 31
SuperLean.exe!improved::tcp_reader::OnRead(std::error_code ec, int bytesRead) Line 254
SuperLean.exe!improved::detail::CompletionWithSizeT<<lambda_ee38b7a750c7f550b4ee1dd60c2450c1> >::Invoke(std::error_code ec, int count) Line 31
SuperLean.exe!improved::tcp_reader::OnRead(std::error_code ec, int bytesRead) Line 254
SuperLean.exe!improved::detail::CompletionWithSizeT<<lambda_ee38b7a750c7f550b4ee1dd60c2450c1> >::Invoke(std::error_code ec, int count) Line 31
SuperLean.exe!improved::tcp_reader::OnRead(std::error_code ec, int bytesRead) Line 254
SuperLean.exe!improved::detail::CompletionWithSizeT<<lambda_ee38b7a750c7f550b4ee1dd60c2450c1> >::Invoke(std::error_code ec, int count) Line 31
SuperLean.exe!improved::tcp_reader::OnRead(std::error_code ec, int bytesRead) Line 254
SuperLean.exe!improved::detail::CompletionWithSizeT<<lambda_ee38b7a750c7f550b4ee1dd60c2450c1> >::Invoke(std::error_code ec, int count) Line 31
SuperLean.exe!improved::tcp_reader::OnRead(std::error_code ec, int bytesRead) Line 254
SuperLean.exe!improved::detail::CompletionWithSizeT<<lambda_ee38b7a750c7f550b4ee1dd60c2450c1> >::Invoke(std::error_code ec, int count) Line 31
SuperLean.exe!improved::tcp_reader::OnRead(std::error_code ec, int bytesRead) Line 254
SuperLean.exe!improved::detail::CompletionWithSizeT<<lambda_ee38b7a750c7f550b4ee1dd60c2450c1> >::Invoke(std::error_code ec, int count) Line 31
SuperLean.exe!improved::tcp_reader::OnRead(std::error_code ec, int bytesRead) Line 254
SuperLean.exe!improved::detail::CompletionWithSizeT<<lambda_ee38b7a750c7f550b4ee1dd60c2450c1> >::Invoke(std::error_code ec, int count) Line 31
SuperLean.exe!improved::tcp_reader::OnRead(std::error_code ec, int bytesRead) Line 254
SuperLean.exe!improved::detail::CompletionWithSizeT<<lambda_ee38b7a750c7f550b4ee1dd60c2450c1> >::Invoke(std::error_code ec, int count) Line 31
SuperLean.exe!improved::tcp_reader::OnRead(std::error_code ec, int bytesRead) Line 254
SuperLean.exe!improved::detail::CompletionWithSizeT<<lambda_ee38b7a750c7f550b4ee1dd60c2450c1> >::Invoke(std::error_code ec, int count) Line 31
SuperLean.exe!improved::tcp_reader::OnRead(std::error_code ec, int bytesRead) Line 254
SuperLean.exe!improved::detail::CompletionWithSizeT<<lambda_ee38b7a750c7f550b4ee1dd60c2450c1> >::Invoke(std::error_code ec, int count) Line 31
SuperLean.exe!improved::tcp_reader::OnRead(std::error_code ec, int bytesRead) Line 254
SuperLean.exe!improved::detail::CompletionWithSizeT<<lambda_ee38b7a750c7f550b4ee1dd60c2450c1> >::Invoke(std::error_code ec, int count) Line 31
SuperLean.exe!improved::tcp_reader::OnRead(std::error_code ec, int bytesRead) Line 254
SuperLean.exe!improved::detail::CompletionWithSizeT<<lambda_ee38b7a750c7f550b4ee1dd60c2450c1> >::Invoke(std::error_code ec, int count) Line 31
SuperLean.exe!improved::tcp_reader::OnRead(std::error_code ec, int bytesRead) Line 254
SuperLean.exe!improved::detail::CompletionWithSizeT<<lambda_ee38b7a750c7f550b4ee1dd60c2450c1> >::Invoke(std::error_code ec, int count) Line 31
SuperLean.exe!improved::detail::io_complete_callback(CompletionPacket & p) Line 22
SuperLean.exe!CompletionQueue::ThreadProc(void * lpParameter) Line 112 C++
Stack
Overflow
Need to implement it on the use side
C++ Russia 2016 Coroutines 44
void tcp_reader::OnRead(std::error_code ec, int bytesRead) {
if (ec) return OnError(ec);
total -= (int)bytesRead;
if (total <= 0 || bytesRead == 0) return OnComplete();
bytesRead = sizeof(buf);
conn.Read(buf, bytesRead,
[this](std::error_code ec, int bytesRead) {
OnRead(ec, bytesRead); }) ;
}
Now handling synchronous completion
C++ Russia 2016 Coroutines 45
void tcp_reader::OnRead(std::error_code ec, int bytesRead) {
do {
if (ec) return OnError(ec);
total -= (int)bytesRead;
if (total <= 0 || bytesRead == 0) return OnComplete();
bytesRead = sizeof(buf);
} while (
conn.Read(buf, bytesRead,
[this](std::error_code ec, int bytesRead) {
OnRead(ec, bytesRead); }));
}
Let’s measure the improvement (handwritten)
C++ Russia 2016 Coroutines 46
Handcrafted Coroutine Handcrafted Coroutine
Original 380 495 30 25
Synchr Completion. Opt
MB/s Executable size
485
25
30
auto Connection::Read(void* buf, int len) {
struct awaiter: AwaiterBase {
Connection* me;
void* buf;
awaiter(Connection* me, void* buf, int len) : me(me), buf(buf) { bytes = len; }
bool await_ready() { return false; }
void await_suspend(coroutine_handle<> h) {
this->resume = h;
auto error = me->sock.Receive(buf, bytes, this);
if (error.value() == kIoPending) return;
if (error) throw system_error(err);
return;
}
int await_resume() {
if (this->err) throw system_error(err);
return bytes;
}
};
return awaiter{ this, buf, len };
} C++ Russia 2016 Coroutines 47
struct AwaiterBase : os_async_context {
coroutine_handle<> resume;
std::error_code err;
int bytes;
static void io_complete_callback(CompletionPacket& p){
auto me = static_cast<AwaiterBase*>(p.overlapped);
me->err = p.error;
me->bytes = p.byteTransferred;
me->resume();
}
};
SetFileCompletionNotificationModes(h,
FILE_SKIP_COMPLETION_PORT_ON_SUCCESS);
auto Connection::Read(void* buf, int len) {
struct awaiter: AwaiterBase {
Connection* me;
void* buf;
awaiter(Connection* me, void* buf, int len) : me(me), buf(buf) { bytes = len; }
bool await_ready() { return false; }
bool await_suspend(coroutine_handle<> h) {
this->resume = h;
auto error = me->sock.Receive(buf, bytes, this);
if (error.value() == kIoPending) return true;
if (error) throw system_error(err);
return false;
}
int await_resume() {
if (this->err) throw system_error(err);
return bytes;
}
};
return awaiter{ this, buf, len };
} C++ Russia 2016 Coroutines 48
struct AwaiterBase : os_async_context {
coroutine_handle<> resume;
std::error_code err;
int bytes;
static void io_complete_callback(CompletionPacket& p){
auto me = static_cast<AwaiterBase*>(p.overlapped);
me->err = p.error;
me->bytes = p.byteTransferred;
me->resume();
}
};
await <expr>
C++ Russia 2016 Coroutines
Expands into an expression equivalent of
{
auto && tmp = operator co_await <expr>;
if (! tmp.await_ready()) {
tmp.await_suspend(<coroutine-handle>);
}
return tmp.await_resume();
}
suspend
resume
49
await <expr>
C++ Russia 2016 Coroutines
Expands into an expression equivalent of
{
auto && tmp = operator await(opt) <expr>;
if (! tmp.await_ready() &&
tmp.await_suspend(<coroutine-handle>) {
}
return tmp.await_resume();
}
suspend
resume
50
Let’s measure the improvement (coroutine)
C++ Russia 2016 Coroutines 51
Handcrafted Coroutine Handcrafted Coroutine
Original 380 495 30 25
Synchr Completion. Opt 485 30
MB/s Executable size
1028
25
25
Can we make it better?
C++ Russia 2016 Coroutines 53
Getting rid of the allocations
C++ Russia 2016 Coroutines 54
class tcp_reader {
std::unique_ptr<detail::OverlappedBase> wo;
…
tcp_reader(int64_t total) : total(total) {
wo = detail::make_handler_with_count(
[this](auto ec, int nBytes) {OnRead(ec, nBytes); });
…
}
void OnRead(std::error_code ec, int bytesRead) {
if (ec) return OnError(ec);
do {
total -= (int)bytesRead;
if (total <= 0 || bytesRead == 0) return OnComplete();
bytesRead = sizeof(buf);
} while (conn.Read(buf, bytesRead, wo.get()));
}
Let’s measure the improvement (handcrafted)
C++ Russia 2016 Coroutines 55
Handcrafted Coroutine Handcrafted Coroutine
Original 380 495 30 25
Synchr Completion. Opt 485 1028 30 25
Prealloc handler 1028 25
MB/s Executable size
690
25
28
Coroutines are popular!
Python: PEP 0492
async def abinary(n):
if n <= 0:
return 1
l = await abinary(n - 1)
r = await abinary(n - 1)
return l + 1 + r
HACK (programming language)
async function gen1(): Awaitable<int> {
$x = await Batcher::fetch(1);
$y = await Batcher::fetch(2);
return $x + $y;
}
DART 1.9
Future<int> getPage(t) async {
var c = new http.Client();
try {
var r = await c.get('http://url/search?q=$t');
print(r);
return r.length();
} finally {
await c.close();
}
}
C#
async Task<string> WaitAsynchronouslyAsync()
{
await Task.Delay(10000);
return "Finished";
}
C++17
future<string> WaitAsynchronouslyAsync()
{
await sleep_for(10ms);
return "Finished“s;
}
C++ Russia 2016 Coroutines 56
Cosmetics (Nov 2015, keyword change)
co_await
co_yield
co_return
C++ Russia 2016 Coroutines 57
Generalized Function
C++ Russia 2016 Coroutines 58
Compiler
User
Coroutine
Designer
Async
Generator
await + yield
Generator
yield
Task
await
Monadic*
await - suspend
POF
does not careimage credits: Три богатыря и змей горыныч
Design Principles
• Scalable (to billions of concurrent coroutines)
• Efficient (resume and suspend operations comparable in cost
to a function call overhead)
• Seamless interaction with existing facilities with no overhead
• Open ended coroutine machinery allowing library designers to
develop coroutine libraries exposing various high-level
semantics, such as generators, goroutines, tasks and more.
• Usable in environments where exceptions are forbidden or not
available
59C++ Russia 2016 Coroutines
C++ Russia 2016 Coroutines 60
Coroutine implementation
strategies
C++ Russia 2016 Coroutines 61
C++ Russia 2016 Coroutines 64
Return Address
Locals of F
Parameters of F
Thread Stack
F’s Activation
Record
…
Return Address
Locals of G
Parameters of G
G’s Activation
Record
Return Address
Locals of H
Parameters of H
H’s Activation
Record
Stack Pointer
Stack Pointer
Stack Pointer Normal Functions
C++ Russia 2016 Coroutines 65
Return Address
Locals of F
Parameters of F
Thread 1 Stack
F’s Activation
Record
…
Return Address
Locals of G
Parameters of G
G’s Activation
Record
Return Address
Locals of H
Parameters of H
H’s Activation
Record
Stack Pointer
Stack Pointer
Stack Pointer Normal Functions
C++ Russia 2016 Coroutines 66
Return Address
Locals of F
Parameters of F
Thread 1 Stack
F’s Activation
Record
…
Return Address
Locals of H
Parameters of H
H’s Activation
Record
Stack Pointer
Coroutines using Fibers (first call)
Stack Pointer
Locals of G
Parameters of G
Return Address
Fiber Context
Old Stack Top
Saved Registers
Fiber Stack
Fiber Start
Routine
Thread Context:
IP,RSP,RAX,RCX
RDX,…
RDI,
etc
Saved Registers
C++ Russia 2016 Coroutines 67
Return Address
Locals of F
Parameters of F
Thread 1 Stack
F’s Activation
Record
…
Return Address
Locals of H
Parameters of H
H’s Activation
Record
Coroutines using Fibers (Suspend)
Stack Pointer
Locals of G
Parameters of G
Return Address
Fiber Context
Old Stack Top
Saved Registers
Fiber Stack
Fiber Start
Routine
Thread Context:
IP,RSP,RAX,RCX
RDX,…
RDI,RSI,
etc
Saved RegistersSaved Registers
C++ Russia 2016 Coroutines 68
Return Address
Locals of Z
Parameters of Z
Thread 2 Stack
Z’s Activation
Record
…
Return Address
Locals of H
Parameters of H
H’s Activation
Record
Stack Pointer
Coroutines using Fibers (Resume)
Locals of G
Parameters of G
Return Address
Fiber Context
Old Stack Top
Saved Registers
Fiber Stack
Fiber Start
Routine
Saved Registers
Return Address
Saved Registers
https://github.com/mirror/boost/blob/master/libs/context/src/asm/jump_x86_64_ms_pe_masm.asm (1/2)
C++ Russia 2016 Coroutines 69
https://github.com/mirror/boost/blob/master/libs/context/src/asm/jump_x86_64_ms_pe_masm.asm (2/2)
C++ Russia 2016 Coroutines 70
Mitigating Memory Footprint
Fiber State
1 meg of stack
(chained stack)
4k stacklet
4k stacklet
4k stacklet
4k stacklet
…
4k stacklet
C++ Russia 2016 Coroutines 71
(reallocate and copy)
2k stack
4k stack
…
1k stack
8k stack
16k stack
Design Principles
• Scalable (to billions of concurrent coroutines)
• Efficient (resume and suspend operations comparable in cost
to a function call overhead)
• Seamless interaction with existing facilities with no overhead
• Open ended coroutine machinery allowing library designers to
develop coroutine libraries exposing various high-level
semantics, such as generators, goroutines, tasks and more.
• Usable in environments where exceptions are forbidden or not
available
72C++ Russia 2016 Coroutines
Compiler based coroutines
C++ Russia 2016 Coroutines 73
generator<int> f() {
for (int i = 0; i < 5; ++i) {
yield i;
}
generator<int> f() {
f$state *mem = __coro_elide()
? alloca(f$state) : new f$state;
mem->__resume_fn = &f$resume;
mem->__destroy_fn = &f$resume;
return {mem};
}
struct f$state {
void* __resume_fn;
void* __destroy_fn;
int __resume_index = 0;
int i;
};
void f$resume(f$state s) {
switch (s->__resume_index) {
case 0: s->i = 0; s->resume_index = 1; break;
case 1: if( ++s->i == 5) s->resume_address = nullptr; break;
}
}
int main() {
for (int v: f())
printf(“%dn”, v);
}
void f$destroy(f$state s) {
if(!__coro_elide()) delete f$state;
}
int main() {
printf(“%dn”, 0);
printf(“%dn”, 1);
printf(“%dn”, 2);
printf(“%dn”, 3);
printf(“%dn”, 4);
}
C++ Russia 2016 Coroutines 74
Return Address
Locals of F
Parameters of F
Thread 1 Stack
F’s Activation
Record
…
Return Address
Locals of G
Parameters of G
G’s Activation
Record (Coroutine)
Return Address
Locals of H
Parameters of H
H’s Activation
Record
Stack Pointer
Stack Pointer
Stack Pointer Compiler Based Coroutines
struct G$state {
void* __resume_fn;
void* __destroy_fn;
int __resume_index;
locals, temporaries
that need to preserve values
across suspend points
};
G’s Coroutine
State
C++ Russia 2016 Coroutines 75
Return Address
Locals of F
Parameters of F
Thread 1 Stack
F’s Activation
Record
…
Return Address
Locals of G
Parameters of G
G’s Activation
Record
Return Address
Locals of H
Parameters of H
H’s Activation
Record
Stack Pointer
Stack Pointer
Stack Pointer Compiler Based Coroutines
(Suspend)
struct G$state {
void* __resume_fn;
void* __destroy_fn;
int __resume_index;
locals, temporaries
that need to preserve values
across suspend points
};
G’s Coroutine
State
C++ Russia 2016 Coroutines 76
Return Address
Locals of X
Parameters of X
Thread 2 Stack
X’s Activation
Record
…
Return Address
Locals of
g$resume
Parameters of
g$resume
G$resume’s
Activation
Record
Return Address
Locals of H
Parameters of H
H’s Activation
Record
Stack Pointer
Stack Pointer
Stack Pointer Compiler Based Coroutines
(Resume)
struct G$state {
void* __resume_fn;
void* __destroy_fn;
int __resume_index;
locals, temporaries
that need to preserve values
across suspend points
};
G’s Coroutine
State
Design Principles
• Scalable (to billions of concurrent coroutines)
• Efficient (resume and suspend operations comparable in cost
to a function call overhead)
• Seamless interaction with existing facilities with no overhead
• Open ended coroutine machinery allowing library designers to
develop coroutine libraries exposing various high-level
semantics, such as generators, goroutines, tasks and more.
• Usable in environments where exceptions are forbidden or not
available
77C++ Russia 2016 Coroutines
2 x 2 x 2
• Two new keywords
•await
•yield
syntactic sugar for: await $p.yield_value(expr)
• Two new concepts
•Awaitable
•Coroutine Promise
•Two library types
• coroutine_handle
• coroutine_traits
C++ Russia 2016 Coroutines 79
After Kona 2015
co_await
co_yield
co_return
Trivial Awaitable #1
C++ Russia 2016 Coroutines 80
struct _____blank____ {
bool await_ready(){ return false; }
template <typename F>
void await_suspend(F){}
void await_resume(){}
};
Trivial Awaitable #1
C++ Russia 2016 Coroutines 81
struct suspend_always {
bool await_ready(){ return false; }
template <typename F>
void await_suspend(F){}
void await_resume(){}
};
await suspend_always {};
Trivial Awaitable #2
C++ Russia 2016 Coroutines 82
struct suspend_never {
bool await_ready(){ return true; }
template <typename F>
void await_suspend(F){}
void await_resume(){}
};
Simple Awaitable #1
C++ Russia 2016 Coroutines 83
std::future<void> DoSomething(mutex& m) {
unique_lock<mutex> lock = await lock_or_suspend{m};
// ...
}
struct lock_or_suspend {
std::unique_lock<std::mutex> lock;
lock_or_suspend(std::mutex & mut) : lock(mut, std::try_to_lock) {}
bool await_ready() { return lock.owns_lock(); }
template <typename F>
void await_suspend(F cb)
{
std::thread t([this, cb]{ lock.lock(); cb(); });
t.detach();
}
auto await_resume() { return std::move(lock);}
};
Awaitable
Interacting with C APIs
C++ Russia 2016 Coroutines 84
2 x 2 x 2
• Two new keywords
•await
•yield
syntactic sugar for: await $p.yield_value(expr)
• Two new concepts
•Awaitable
•Coroutine Promise
•Two library types
• coroutine_handle
• coroutine_traits
C++ Russia 2016 Coroutines 85
After Kona 2015
co_await
co_yield
co_return
coroutine_handle
C++ Russia 2016 Coroutines 86
template <typename Promise = void> struct coroutine_handle;
template <> struct coroutine_handle<void> {
void resume();
void destroy();
bool done() const;
void * address();
static coroutine_handle from_address(void*);
void operator()(); // same as resume()
…
};
== != < > <= >=
Simple Awaitable #2: Raw OS APIs
await 10ms;
C++ Russia 2016 Coroutines 87
class awaiter {
static void CALLBACK TimerCallback(PTP_CALLBACK_INSTANCE, void *Context, PTP_TIMER) {
std::experimental::coroutine_handle<>::from_address(Context).resume();
}
PTP_TIMER timer = nullptr;
std::chrono::system_clock::duration duration;
public:
explicit awaiter(std::chrono::system_clock::duration d) : duration(d) {}
bool await_ready() const { return duration.count() <= 0; }
void await_suspend(std::experimental::coroutine_handle<> resume_cb) {
timer = CreateThreadpoolTimer(TimerCallback, resume_cb.address(), nullptr);
if (!timer) throw std::bad_alloc();
int64_t relative_count = -duration.count();
SetThreadpoolTimer(timer, (PFILETIME)&relative_count, 0, 0);
}
void await_resume() {}
~awaiter() { if (timer) CloseThreadpoolTimer(timer); }
}; auto operator await(std::chrono::system_clock::duration duration) {
return awaiter{duration};
}
2 x 2 x 2
• Two new keywords
•await
•yield
syntactic sugar for: await $p.yield_value(expr)
• Two new concepts
•Awaitable
•Coroutine Promise
•Two library types
• coroutine_handle
• coroutine_traits
C++ Russia 2016 Coroutines 88
After Kona 2015
co_await
co_yield
co_return
coroutine_traits
C++ Russia 2016 Coroutines 89
template <typename R, typename... Ts>
struct coroutine_traits {
using promise_type = typename R::promise_type;
};
generator<int> fib(int n)
std::coroutine_traits<generator<int>, int>
Compiler vs Coroutine Promise
yield <expr> await <Promise>.yield_value(<expr>)
<before-last-curly>
return <expr> <Promise>.return_value(<expr>);
goto <end>
<after-first-curly>
<unhandled-exception> <Promise>.set_exception (
std::current_exception())
<get-return-object> <Promise>.get_return_object()
await <Promise>.initial_suspend()
await <Promise>.final_suspend()
C++ Russia 2016 Coroutines 90
await <expr> Spent the last hour talking about it
<allocate coro-state> <Promise>.operator new (or global)
<free coro-state> <Promise>.operator delete (or global)
Defining Coroutine Promise
for boost::future
namespace std {
template <typename T, typename… anything>
struct coroutine_traits<boost::unique_future<T>, anything…> {
struct promise_type {
boost::promise<T> promise;
auto get_return_object() { return promise.get_future(); }
template <class U> void return_value(U && value) {
promise.set_value(std::forward<U>(value));
}
void set_exception(std::exception_ptr e) {
promise.set_exception(std::move(e));
}
std::suspend_never initial_suspend() { return {}; }
std::suspend_never final_suspend() { return {}; }
};
};
}
C++ Russia 2016 Coroutines 91
coroutine_handle<promise>
C++ Russia 2016 Coroutines 92
template <typename Promise = void> struct coroutine_handle;
template <> struct coroutine_handle<void> {
void resume();
void destroy();
bool done() const;
void * address();
static coroutine_handle from_address(void*);
void operator()(); // same as resume()
…
};
template < typename Promise>
struct coroutine_handle: coroutine_handle<void> {
Promise & promise();
static coroutine_handle from_promise(Promise&);
};
== != < > <= >=
Defining Generator From Scratch
C++ Russia 2016 Coroutines 93
struct int_generator {
bool move_next();
int current_value();
…
};
int_generator f() {
for (int i = 0; i < 5; i++) {
yield i;
}
int main() {
auto g = f ();
while (g.move_next()) {
printf("%dn", g.current_value());
}
}
C++ Russia 2016 Coroutines 94
struct int_generator {
struct promise_type {
int current_value;
std::suspend_always yield_value(int value) {
this->current_value = value;
return{};
}
std::suspend_always initial_suspend() { return{}; }
std::suspend_always final_suspend() { return{}; }
int_generator get_return_object() { return int_generator{ this }; };
};
bool move_next() { p.resume(); return !p.done(); }
int current_value() { return p.promise().current_value; }
~int_generator() { p.destroy(); }
private:
explicit int_generator(promise_type *p)
: p(std::coroutine_handle<promise_type>::from_promise(*p)) {}
std::coroutine_handle<promise_type> p;
};
Defining Generator From Scratch
yield <expr> await <Promise>.yield_value(<expr>)
C++ Russia 2016 Coroutines 95
STL looks like the machine language macro library of
an anally retentive assembly language programmer
Pamela Seymour, Leiden University
C++ Coroutines: Layered complexity
• Everybody
• Safe by default, novice friendly
Use coroutines and awaitables defined by standard library, boost and
other high quality libraries
• Power Users
• Define new awaitables to customize await for their
environment using existing coroutine types
• Experts
• Define new coroutine types
C++ Russia 2016 Coroutines 96
Thank you!
C++ Russia 2016 Coroutines 97
Kavya Kotacherry, Daveed Vandevoorde, Richard Smith, Jens Maurer,
Lewis Baker, Kirk Shoop, Hartmut Kaiser, Kenny Kerr, Artur Laksberg, Jim
Radigan, Chandler Carruth, Gabriel Dos Reis, Deon Brewis, Jonathan
Caves, James McNellis, Stephan T. Lavavej, Herb Sutter, Pablo Halpern,
Robert Schumacher, Viktor Tong, Geoffrey Romer, Michael Wong, Niklas
Gustafsson, Nick Maliwacki, Vladimir Petter, Shahms King, Slava
Kuznetsov, Tongari J, Lawrence Crowl, Valentin Isac
and many more who contributed
Coroutines – a negative overhead abstraction
C++ Russia 2016 Coroutines 98
• Proposal is working through C++ standardization committee
(C++17?)
• Experimental implementation in VS 2015 RTM
• Clang implementation is in progress
• more details:
• http://www.open-
std.org/JTC1/SC22/WG21/docs/papers/2016/P0057R2.pdf
Questions?
C++ Russia 2016 Coroutines 99

More Related Content

What's hot

Android Storage - Vold
Android Storage - VoldAndroid Storage - Vold
Android Storage - VoldWilliam Lee
 
Android's HIDL: Treble in the HAL
Android's HIDL: Treble in the HALAndroid's HIDL: Treble in the HAL
Android's HIDL: Treble in the HALOpersys inc.
 
Inter-process communication of Android
Inter-process communication of AndroidInter-process communication of Android
Inter-process communication of AndroidTetsuyuki Kobayashi
 
Exception handling and templates
Exception handling and templatesException handling and templates
Exception handling and templatesfarhan amjad
 
Understanding the Android System Server
Understanding the Android System ServerUnderstanding the Android System Server
Understanding the Android System ServerOpersys inc.
 
Reusing your existing software on Android
Reusing your existing software on AndroidReusing your existing software on Android
Reusing your existing software on AndroidTetsuyuki Kobayashi
 
Go Profiling - John Graham-Cumming
Go Profiling - John Graham-Cumming Go Profiling - John Graham-Cumming
Go Profiling - John Graham-Cumming Cloudflare
 
Overview of Android binder IPC implementation
Overview of Android binder IPC implementationOverview of Android binder IPC implementation
Overview of Android binder IPC implementationChethan Pchethan
 
Android's Multimedia Framework
Android's Multimedia FrameworkAndroid's Multimedia Framework
Android's Multimedia FrameworkOpersys inc.
 
History & Practices for UniRx(EN)
History & Practices for UniRx(EN)History & Practices for UniRx(EN)
History & Practices for UniRx(EN)Yoshifumi Kawai
 
Binderのはじめの一歩とAndroid
Binderのはじめの一歩とAndroidBinderのはじめの一歩とAndroid
Binderのはじめの一歩とAndroidl_b__
 

What's hot (20)

Android Storage - Vold
Android Storage - VoldAndroid Storage - Vold
Android Storage - Vold
 
Android's HIDL: Treble in the HAL
Android's HIDL: Treble in the HALAndroid's HIDL: Treble in the HAL
Android's HIDL: Treble in the HAL
 
Inter-process communication of Android
Inter-process communication of AndroidInter-process communication of Android
Inter-process communication of Android
 
C++ Coroutines
C++ CoroutinesC++ Coroutines
C++ Coroutines
 
Embedded Android : System Development - Part IV (Android System Services)
Embedded Android : System Development - Part IV (Android System Services)Embedded Android : System Development - Part IV (Android System Services)
Embedded Android : System Development - Part IV (Android System Services)
 
Exception handling and templates
Exception handling and templatesException handling and templates
Exception handling and templates
 
Explore Android Internals
Explore Android InternalsExplore Android Internals
Explore Android Internals
 
Understanding the Android System Server
Understanding the Android System ServerUnderstanding the Android System Server
Understanding the Android System Server
 
Embedded Android : System Development - Part II (HAL)
Embedded Android : System Development - Part II (HAL)Embedded Android : System Development - Part II (HAL)
Embedded Android : System Development - Part II (HAL)
 
Android Internals
Android InternalsAndroid Internals
Android Internals
 
Reusing your existing software on Android
Reusing your existing software on AndroidReusing your existing software on Android
Reusing your existing software on Android
 
Stack and heap
Stack and heapStack and heap
Stack and heap
 
Go Profiling - John Graham-Cumming
Go Profiling - John Graham-Cumming Go Profiling - John Graham-Cumming
Go Profiling - John Graham-Cumming
 
Overview of Android binder IPC implementation
Overview of Android binder IPC implementationOverview of Android binder IPC implementation
Overview of Android binder IPC implementation
 
Hacking Android OS
Hacking Android OSHacking Android OS
Hacking Android OS
 
Golang Channels
Golang ChannelsGolang Channels
Golang Channels
 
Android's Multimedia Framework
Android's Multimedia FrameworkAndroid's Multimedia Framework
Android's Multimedia Framework
 
History & Practices for UniRx(EN)
History & Practices for UniRx(EN)History & Practices for UniRx(EN)
History & Practices for UniRx(EN)
 
Embedded Android : System Development - Part III (Audio / Video HAL)
Embedded Android : System Development - Part III (Audio / Video HAL)Embedded Android : System Development - Part III (Audio / Video HAL)
Embedded Android : System Development - Part III (Audio / Video HAL)
 
Binderのはじめの一歩とAndroid
Binderのはじめの一歩とAndroidBinderのはじめの一歩とAndroid
Binderのはじめの一歩とAndroid
 

Viewers also liked

Async await in C++
Async await in C++Async await in C++
Async await in C++cppfrug
 
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионаловПолухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионаловSergey Platonov
 
Использование юнит-тестов для повышения качества разработки
Использование юнит-тестов для повышения качества разработкиИспользование юнит-тестов для повышения качества разработки
Использование юнит-тестов для повышения качества разработкиvictor-yastrebov
 
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...Platonov Sergey
 
Фитнес для вашего кода: как держать его в форме
Фитнес для вашего кода: как держать его в формеФитнес для вашего кода: как держать его в форме
Фитнес для вашего кода: как держать его в формеIlia Shishkov
 
Evgeniy Muralev, Mark Vince, Working with the compiler, not against it
Evgeniy Muralev, Mark Vince, Working with the compiler, not against itEvgeniy Muralev, Mark Vince, Working with the compiler, not against it
Evgeniy Muralev, Mark Vince, Working with the compiler, not against itSergey Platonov
 
C++ Core Guidelines
C++ Core Guidelines C++ Core Guidelines
C++ Core Guidelines Sergey Zubkov
 
Fuzzing: The New Unit Testing
Fuzzing: The New Unit TestingFuzzing: The New Unit Testing
Fuzzing: The New Unit TestingDmitry Vyukov
 
Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017
Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017
Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017Mikhail Matrosov
 
Василий Сорокин, Простой REST сервер на Qt с рефлексией
Василий Сорокин, Простой REST сервер на Qt с рефлексиейВасилий Сорокин, Простой REST сервер на Qt с рефлексией
Василий Сорокин, Простой REST сервер на Qt с рефлексиейSergey Platonov
 
Антон Бикинеев, Reflection in C++Next
Антон Бикинеев,  Reflection in C++NextАнтон Бикинеев,  Reflection in C++Next
Антон Бикинеев, Reflection in C++NextSergey Platonov
 
Григорий Демченко, Универсальный адаптер
Григорий Демченко, Универсальный адаптерГригорий Демченко, Универсальный адаптер
Григорий Демченко, Универсальный адаптерSergey Platonov
 
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и Javascript
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и JavascriptСергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и Javascript
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и JavascriptSergey Platonov
 
Алексей Кутумов, C++ без исключений, часть 3
Алексей Кутумов,  C++ без исключений, часть 3Алексей Кутумов,  C++ без исключений, часть 3
Алексей Кутумов, C++ без исключений, часть 3Platonov Sergey
 
Догнать и перегнать boost::lexical_cast
Догнать и перегнать boost::lexical_castДогнать и перегнать boost::lexical_cast
Догнать и перегнать boost::lexical_castRoman Orlov
 
Для чего мы делали свой акторный фреймворк и что из этого вышло?
Для чего мы делали свой акторный фреймворк и что из этого вышло?Для чего мы делали свой акторный фреймворк и что из этого вышло?
Для чего мы делали свой акторный фреймворк и что из этого вышло?Yauheni Akhotnikau
 
Quality assurance of large c++ projects
Quality assurance of large c++ projectsQuality assurance of large c++ projects
Quality assurance of large c++ projectscorehard_by
 
Дмитрий Демчук. Кроссплатформенный краш-репорт
Дмитрий Демчук. Кроссплатформенный краш-репортДмитрий Демчук. Кроссплатформенный краш-репорт
Дмитрий Демчук. Кроссплатформенный краш-репортSergey Platonov
 

Viewers also liked (20)

Async await in C++
Async await in C++Async await in C++
Async await in C++
 
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионаловПолухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
 
Использование юнит-тестов для повышения качества разработки
Использование юнит-тестов для повышения качества разработкиИспользование юнит-тестов для повышения качества разработки
Использование юнит-тестов для повышения качества разработки
 
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
 
Parallel STL
Parallel STLParallel STL
Parallel STL
 
Фитнес для вашего кода: как держать его в форме
Фитнес для вашего кода: как держать его в формеФитнес для вашего кода: как держать его в форме
Фитнес для вашего кода: как держать его в форме
 
Evgeniy Muralev, Mark Vince, Working with the compiler, not against it
Evgeniy Muralev, Mark Vince, Working with the compiler, not against itEvgeniy Muralev, Mark Vince, Working with the compiler, not against it
Evgeniy Muralev, Mark Vince, Working with the compiler, not against it
 
C++ Core Guidelines
C++ Core Guidelines C++ Core Guidelines
C++ Core Guidelines
 
Fuzzing: The New Unit Testing
Fuzzing: The New Unit TestingFuzzing: The New Unit Testing
Fuzzing: The New Unit Testing
 
Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017
Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017
Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017
 
Василий Сорокин, Простой REST сервер на Qt с рефлексией
Василий Сорокин, Простой REST сервер на Qt с рефлексиейВасилий Сорокин, Простой REST сервер на Qt с рефлексией
Василий Сорокин, Простой REST сервер на Qt с рефлексией
 
Антон Бикинеев, Reflection in C++Next
Антон Бикинеев,  Reflection in C++NextАнтон Бикинеев,  Reflection in C++Next
Антон Бикинеев, Reflection in C++Next
 
Григорий Демченко, Универсальный адаптер
Григорий Демченко, Универсальный адаптерГригорий Демченко, Универсальный адаптер
Григорий Демченко, Универсальный адаптер
 
Clang tidy
Clang tidyClang tidy
Clang tidy
 
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и Javascript
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и JavascriptСергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и Javascript
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и Javascript
 
Алексей Кутумов, C++ без исключений, часть 3
Алексей Кутумов,  C++ без исключений, часть 3Алексей Кутумов,  C++ без исключений, часть 3
Алексей Кутумов, C++ без исключений, часть 3
 
Догнать и перегнать boost::lexical_cast
Догнать и перегнать boost::lexical_castДогнать и перегнать boost::lexical_cast
Догнать и перегнать boost::lexical_cast
 
Для чего мы делали свой акторный фреймворк и что из этого вышло?
Для чего мы делали свой акторный фреймворк и что из этого вышло?Для чего мы делали свой акторный фреймворк и что из этого вышло?
Для чего мы делали свой акторный фреймворк и что из этого вышло?
 
Quality assurance of large c++ projects
Quality assurance of large c++ projectsQuality assurance of large c++ projects
Quality assurance of large c++ projects
 
Дмитрий Демчук. Кроссплатформенный краш-репорт
Дмитрий Демчук. Кроссплатформенный краш-репортДмитрий Демчук. Кроссплатформенный краш-репорт
Дмитрий Демчук. Кроссплатформенный краш-репорт
 

Similar to Gor Nishanov, C++ Coroutines – a negative overhead abstraction

NVIDIA HPC ソフトウエア斜め読み
NVIDIA HPC ソフトウエア斜め読みNVIDIA HPC ソフトウエア斜め読み
NVIDIA HPC ソフトウエア斜め読みNVIDIA Japan
 
Config interface
Config interfaceConfig interface
Config interfaceRyan Boland
 
Concurrency in go
Concurrency in goConcurrency in go
Concurrency in goborderj
 
The CppCat Analyzer Checks TortoiseGit
The CppCat Analyzer Checks TortoiseGitThe CppCat Analyzer Checks TortoiseGit
The CppCat Analyzer Checks TortoiseGitAndrey Karpov
 
A Physical Units Library for the Next C++
A Physical Units Library for the Next C++A Physical Units Library for the Next C++
A Physical Units Library for the Next C++Mateusz Pusz
 
Segmentation Faults, Page Faults, Processes, Threads, and Tasks
Segmentation Faults, Page Faults, Processes, Threads, and TasksSegmentation Faults, Page Faults, Processes, Threads, and Tasks
Segmentation Faults, Page Faults, Processes, Threads, and TasksDavid Evans
 
Let's talks about string operations in C++17
Let's talks about string operations in C++17Let's talks about string operations in C++17
Let's talks about string operations in C++17Bartlomiej Filipek
 
Java Keeps Throttling Up!
Java Keeps Throttling Up!Java Keeps Throttling Up!
Java Keeps Throttling Up!José Paumard
 
4Developers 2018: Beyond c++17 (Mateusz Pusz)
4Developers 2018: Beyond c++17 (Mateusz Pusz)4Developers 2018: Beyond c++17 (Mateusz Pusz)
4Developers 2018: Beyond c++17 (Mateusz Pusz)PROIDEA
 
C++ amp on linux
C++ amp on linuxC++ amp on linux
C++ amp on linuxMiller Lee
 
ESL Anyone?
ESL Anyone? ESL Anyone?
ESL Anyone? DVClub
 
EMBEDDED SYSTEMS 4&5
EMBEDDED SYSTEMS 4&5EMBEDDED SYSTEMS 4&5
EMBEDDED SYSTEMS 4&5PRADEEP
 
Job Queue in Golang
Job Queue in GolangJob Queue in Golang
Job Queue in GolangBo-Yi Wu
 
PVS-Studio team experience: checking various open source projects, or mistake...
PVS-Studio team experience: checking various open source projects, or mistake...PVS-Studio team experience: checking various open source projects, or mistake...
PVS-Studio team experience: checking various open source projects, or mistake...Andrey Karpov
 
C++ 11 Features
C++ 11 FeaturesC++ 11 Features
C++ 11 FeaturesJan Rüegg
 
The present and the future of functional programming in c++
The present and the future of functional programming in c++The present and the future of functional programming in c++
The present and the future of functional programming in c++Alexander Granin
 
C++ Code as Seen by a Hypercritical Reviewer
C++ Code as Seen by a Hypercritical ReviewerC++ Code as Seen by a Hypercritical Reviewer
C++ Code as Seen by a Hypercritical ReviewerAndrey Karpov
 
Community-driven Language Design at TC39 on the JavaScript Pipeline Operator ...
Community-driven Language Design at TC39 on the JavaScript Pipeline Operator ...Community-driven Language Design at TC39 on the JavaScript Pipeline Operator ...
Community-driven Language Design at TC39 on the JavaScript Pipeline Operator ...Igalia
 
JVM Mechanics: When Does the JVM JIT & Deoptimize?
JVM Mechanics: When Does the JVM JIT & Deoptimize?JVM Mechanics: When Does the JVM JIT & Deoptimize?
JVM Mechanics: When Does the JVM JIT & Deoptimize?Doug Hawkins
 

Similar to Gor Nishanov, C++ Coroutines – a negative overhead abstraction (20)

NVIDIA HPC ソフトウエア斜め読み
NVIDIA HPC ソフトウエア斜め読みNVIDIA HPC ソフトウエア斜め読み
NVIDIA HPC ソフトウエア斜め読み
 
Config interface
Config interfaceConfig interface
Config interface
 
Concurrency in go
Concurrency in goConcurrency in go
Concurrency in go
 
The CppCat Analyzer Checks TortoiseGit
The CppCat Analyzer Checks TortoiseGitThe CppCat Analyzer Checks TortoiseGit
The CppCat Analyzer Checks TortoiseGit
 
A Physical Units Library for the Next C++
A Physical Units Library for the Next C++A Physical Units Library for the Next C++
A Physical Units Library for the Next C++
 
Segmentation Faults, Page Faults, Processes, Threads, and Tasks
Segmentation Faults, Page Faults, Processes, Threads, and TasksSegmentation Faults, Page Faults, Processes, Threads, and Tasks
Segmentation Faults, Page Faults, Processes, Threads, and Tasks
 
Let's talks about string operations in C++17
Let's talks about string operations in C++17Let's talks about string operations in C++17
Let's talks about string operations in C++17
 
Java Keeps Throttling Up!
Java Keeps Throttling Up!Java Keeps Throttling Up!
Java Keeps Throttling Up!
 
4Developers 2018: Beyond c++17 (Mateusz Pusz)
4Developers 2018: Beyond c++17 (Mateusz Pusz)4Developers 2018: Beyond c++17 (Mateusz Pusz)
4Developers 2018: Beyond c++17 (Mateusz Pusz)
 
C++ amp on linux
C++ amp on linuxC++ amp on linux
C++ amp on linux
 
ESL Anyone?
ESL Anyone? ESL Anyone?
ESL Anyone?
 
EMBEDDED SYSTEMS 4&5
EMBEDDED SYSTEMS 4&5EMBEDDED SYSTEMS 4&5
EMBEDDED SYSTEMS 4&5
 
Job Queue in Golang
Job Queue in GolangJob Queue in Golang
Job Queue in Golang
 
PVS-Studio team experience: checking various open source projects, or mistake...
PVS-Studio team experience: checking various open source projects, or mistake...PVS-Studio team experience: checking various open source projects, or mistake...
PVS-Studio team experience: checking various open source projects, or mistake...
 
C++ 11 Features
C++ 11 FeaturesC++ 11 Features
C++ 11 Features
 
The present and the future of functional programming in c++
The present and the future of functional programming in c++The present and the future of functional programming in c++
The present and the future of functional programming in c++
 
C++ Code as Seen by a Hypercritical Reviewer
C++ Code as Seen by a Hypercritical ReviewerC++ Code as Seen by a Hypercritical Reviewer
C++ Code as Seen by a Hypercritical Reviewer
 
Beyond C++17
Beyond C++17Beyond C++17
Beyond C++17
 
Community-driven Language Design at TC39 on the JavaScript Pipeline Operator ...
Community-driven Language Design at TC39 on the JavaScript Pipeline Operator ...Community-driven Language Design at TC39 on the JavaScript Pipeline Operator ...
Community-driven Language Design at TC39 on the JavaScript Pipeline Operator ...
 
JVM Mechanics: When Does the JVM JIT & Deoptimize?
JVM Mechanics: When Does the JVM JIT & Deoptimize?JVM Mechanics: When Does the JVM JIT & Deoptimize?
JVM Mechanics: When Does the JVM JIT & Deoptimize?
 

More from Sergey Platonov

Лев Казаркин, Удивительные приключения регистров SSE или в поисках одного бага
Лев Казаркин, Удивительные приключения регистров SSE или в поисках одного багаЛев Казаркин, Удивительные приключения регистров SSE или в поисках одного бага
Лев Казаркин, Удивительные приключения регистров SSE или в поисках одного багаSergey Platonov
 
Антон Бикинеев, Writing good std::future&lt; C++ >
Антон Бикинеев, Writing good std::future&lt; C++ >Антон Бикинеев, Writing good std::future&lt; C++ >
Антон Бикинеев, Writing good std::future&lt; C++ >Sergey Platonov
 
Павел Филонов, Разделяй и управляй вместе с Conan.io
Павел Филонов, Разделяй и управляй вместе с Conan.ioПавел Филонов, Разделяй и управляй вместе с Conan.io
Павел Филонов, Разделяй и управляй вместе с Conan.ioSergey Platonov
 
Григорий Демченко, Асинхронность и неблокирующая синхронизация
Григорий Демченко, Асинхронность и неблокирующая синхронизацияГригорий Демченко, Асинхронность и неблокирующая синхронизация
Григорий Демченко, Асинхронность и неблокирующая синхронизацияSergey Platonov
 
Антон Полухин. C++17
Антон Полухин. C++17Антон Полухин. C++17
Антон Полухин. C++17Sergey Platonov
 
Павел Беликов, Как избежать ошибок, используя современный C++
Павел Беликов, Как избежать ошибок, используя современный C++Павел Беликов, Как избежать ошибок, используя современный C++
Павел Беликов, Как избежать ошибок, используя современный C++Sergey Platonov
 
Денис Кандров, Пушкова Евгения, QSpec: тестирование графических приложений на Qt
Денис Кандров, Пушкова Евгения, QSpec: тестирование графических приложений на QtДенис Кандров, Пушкова Евгения, QSpec: тестирование графических приложений на Qt
Денис Кандров, Пушкова Евгения, QSpec: тестирование графических приложений на QtSergey Platonov
 
Алексей Кутумов, Coroutines everywhere
Алексей Кутумов, Coroutines everywhereАлексей Кутумов, Coroutines everywhere
Алексей Кутумов, Coroutines everywhereSergey Platonov
 
Дмитрий Нестерук, Паттерны проектирования в XXI веке
Дмитрий Нестерук, Паттерны проектирования в XXI векеДмитрий Нестерук, Паттерны проектирования в XXI веке
Дмитрий Нестерук, Паттерны проектирования в XXI векеSergey Platonov
 
Александр Тарасенко, Использование python для автоматизации отладки С/C++ код...
Александр Тарасенко, Использование python для автоматизации отладки С/C++ код...Александр Тарасенко, Использование python для автоматизации отладки С/C++ код...
Александр Тарасенко, Использование python для автоматизации отладки С/C++ код...Sergey Platonov
 
Павел Довгалюк, Обратная отладка
Павел Довгалюк, Обратная отладкаПавел Довгалюк, Обратная отладка
Павел Довгалюк, Обратная отладкаSergey Platonov
 
Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков
Никита Глушков, К вопросу о реализации кроссплатформенных фреймворковНикита Глушков, К вопросу о реализации кроссплатформенных фреймворков
Никита Глушков, К вопросу о реализации кроссплатформенных фреймворковSergey Platonov
 
Dori Exterman, Considerations for choosing the parallel computing strategy th...
Dori Exterman, Considerations for choosing the parallel computing strategy th...Dori Exterman, Considerations for choosing the parallel computing strategy th...
Dori Exterman, Considerations for choosing the parallel computing strategy th...Sergey Platonov
 
Александр Гранин, Функциональная 'Жизнь': параллельные клеточные автоматы и к...
Александр Гранин, Функциональная 'Жизнь': параллельные клеточные автоматы и к...Александр Гранин, Функциональная 'Жизнь': параллельные клеточные автоматы и к...
Александр Гранин, Функциональная 'Жизнь': параллельные клеточные автоматы и к...Sergey Platonov
 
Александр Фокин, Рефлексия в C++
Александр Фокин, Рефлексия в C++Александр Фокин, Рефлексия в C++
Александр Фокин, Рефлексия в C++Sergey Platonov
 
Антон Нонко, Классические строки в C++
Антон Нонко, Классические строки в C++Антон Нонко, Классические строки в C++
Антон Нонко, Классические строки в C++Sergey Platonov
 
Михаил Матросов, Повседневный С++: boost и STL
Михаил Матросов, Повседневный С++: boost и STLМихаил Матросов, Повседневный С++: boost и STL
Михаил Матросов, Повседневный С++: boost и STLSergey Platonov
 
Борис Сазонов, RAII потоки и CancellationToken в C++
Борис Сазонов, RAII потоки и CancellationToken в C++Борис Сазонов, RAII потоки и CancellationToken в C++
Борис Сазонов, RAII потоки и CancellationToken в C++Sergey Platonov
 
Алексей Кутумов, Вектор с нуля
Алексей Кутумов, Вектор с нуляАлексей Кутумов, Вектор с нуля
Алексей Кутумов, Вектор с нуляSergey Platonov
 
Kirk Shoop, Reactive programming in C++
Kirk Shoop, Reactive programming in C++Kirk Shoop, Reactive programming in C++
Kirk Shoop, Reactive programming in C++Sergey Platonov
 

More from Sergey Platonov (20)

Лев Казаркин, Удивительные приключения регистров SSE или в поисках одного бага
Лев Казаркин, Удивительные приключения регистров SSE или в поисках одного багаЛев Казаркин, Удивительные приключения регистров SSE или в поисках одного бага
Лев Казаркин, Удивительные приключения регистров SSE или в поисках одного бага
 
Антон Бикинеев, Writing good std::future&lt; C++ >
Антон Бикинеев, Writing good std::future&lt; C++ >Антон Бикинеев, Writing good std::future&lt; C++ >
Антон Бикинеев, Writing good std::future&lt; C++ >
 
Павел Филонов, Разделяй и управляй вместе с Conan.io
Павел Филонов, Разделяй и управляй вместе с Conan.ioПавел Филонов, Разделяй и управляй вместе с Conan.io
Павел Филонов, Разделяй и управляй вместе с Conan.io
 
Григорий Демченко, Асинхронность и неблокирующая синхронизация
Григорий Демченко, Асинхронность и неблокирующая синхронизацияГригорий Демченко, Асинхронность и неблокирующая синхронизация
Григорий Демченко, Асинхронность и неблокирующая синхронизация
 
Антон Полухин. C++17
Антон Полухин. C++17Антон Полухин. C++17
Антон Полухин. C++17
 
Павел Беликов, Как избежать ошибок, используя современный C++
Павел Беликов, Как избежать ошибок, используя современный C++Павел Беликов, Как избежать ошибок, используя современный C++
Павел Беликов, Как избежать ошибок, используя современный C++
 
Денис Кандров, Пушкова Евгения, QSpec: тестирование графических приложений на Qt
Денис Кандров, Пушкова Евгения, QSpec: тестирование графических приложений на QtДенис Кандров, Пушкова Евгения, QSpec: тестирование графических приложений на Qt
Денис Кандров, Пушкова Евгения, QSpec: тестирование графических приложений на Qt
 
Алексей Кутумов, Coroutines everywhere
Алексей Кутумов, Coroutines everywhereАлексей Кутумов, Coroutines everywhere
Алексей Кутумов, Coroutines everywhere
 
Дмитрий Нестерук, Паттерны проектирования в XXI веке
Дмитрий Нестерук, Паттерны проектирования в XXI векеДмитрий Нестерук, Паттерны проектирования в XXI веке
Дмитрий Нестерук, Паттерны проектирования в XXI веке
 
Александр Тарасенко, Использование python для автоматизации отладки С/C++ код...
Александр Тарасенко, Использование python для автоматизации отладки С/C++ код...Александр Тарасенко, Использование python для автоматизации отладки С/C++ код...
Александр Тарасенко, Использование python для автоматизации отладки С/C++ код...
 
Павел Довгалюк, Обратная отладка
Павел Довгалюк, Обратная отладкаПавел Довгалюк, Обратная отладка
Павел Довгалюк, Обратная отладка
 
Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков
Никита Глушков, К вопросу о реализации кроссплатформенных фреймворковНикита Глушков, К вопросу о реализации кроссплатформенных фреймворков
Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков
 
Dori Exterman, Considerations for choosing the parallel computing strategy th...
Dori Exterman, Considerations for choosing the parallel computing strategy th...Dori Exterman, Considerations for choosing the parallel computing strategy th...
Dori Exterman, Considerations for choosing the parallel computing strategy th...
 
Александр Гранин, Функциональная 'Жизнь': параллельные клеточные автоматы и к...
Александр Гранин, Функциональная 'Жизнь': параллельные клеточные автоматы и к...Александр Гранин, Функциональная 'Жизнь': параллельные клеточные автоматы и к...
Александр Гранин, Функциональная 'Жизнь': параллельные клеточные автоматы и к...
 
Александр Фокин, Рефлексия в C++
Александр Фокин, Рефлексия в C++Александр Фокин, Рефлексия в C++
Александр Фокин, Рефлексия в C++
 
Антон Нонко, Классические строки в C++
Антон Нонко, Классические строки в C++Антон Нонко, Классические строки в C++
Антон Нонко, Классические строки в C++
 
Михаил Матросов, Повседневный С++: boost и STL
Михаил Матросов, Повседневный С++: boost и STLМихаил Матросов, Повседневный С++: boost и STL
Михаил Матросов, Повседневный С++: boost и STL
 
Борис Сазонов, RAII потоки и CancellationToken в C++
Борис Сазонов, RAII потоки и CancellationToken в C++Борис Сазонов, RAII потоки и CancellationToken в C++
Борис Сазонов, RAII потоки и CancellationToken в C++
 
Алексей Кутумов, Вектор с нуля
Алексей Кутумов, Вектор с нуляАлексей Кутумов, Вектор с нуля
Алексей Кутумов, Вектор с нуля
 
Kirk Shoop, Reactive programming in C++
Kirk Shoop, Reactive programming in C++Kirk Shoop, Reactive programming in C++
Kirk Shoop, Reactive programming in C++
 

Recently uploaded

introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfVishalKumarJha10
 
Chinsurah Escorts ☎️8617697112 Starting From 5K to 15K High Profile Escorts ...
Chinsurah Escorts ☎️8617697112  Starting From 5K to 15K High Profile Escorts ...Chinsurah Escorts ☎️8617697112  Starting From 5K to 15K High Profile Escorts ...
Chinsurah Escorts ☎️8617697112 Starting From 5K to 15K High Profile Escorts ...Nitya salvi
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisamasabamasaba
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerThousandEyes
 
8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech studentsHimanshiGarg82
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsJhone kinadey
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️Delhi Call girls
 
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...kalichargn70th171
 
Pharm-D Biostatistics and Research methodology
Pharm-D Biostatistics and Research methodologyPharm-D Biostatistics and Research methodology
Pharm-D Biostatistics and Research methodologyAnusha Are
 
Exploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfExploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfproinshot.com
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrandmasabamasaba
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...SelfMade bd
 
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionIntroducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionOnePlan Solutions
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providermohitmore19
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsAlberto González Trastoy
 
Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdfPearlKirahMaeRagusta1
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfkalichargn70th171
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️Delhi Call girls
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVshikhaohhpro
 
Azure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdf
Azure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdfAzure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdf
Azure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdfryanfarris8
 

Recently uploaded (20)

introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
 
Chinsurah Escorts ☎️8617697112 Starting From 5K to 15K High Profile Escorts ...
Chinsurah Escorts ☎️8617697112  Starting From 5K to 15K High Profile Escorts ...Chinsurah Escorts ☎️8617697112  Starting From 5K to 15K High Profile Escorts ...
Chinsurah Escorts ☎️8617697112 Starting From 5K to 15K High Profile Escorts ...
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
 
8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
 
Pharm-D Biostatistics and Research methodology
Pharm-D Biostatistics and Research methodologyPharm-D Biostatistics and Research methodology
Pharm-D Biostatistics and Research methodology
 
Exploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfExploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdf
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
 
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionIntroducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdf
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
Azure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdf
Azure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdfAzure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdf
Azure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdf
 

Gor Nishanov, C++ Coroutines – a negative overhead abstraction

  • 1. C++ Coroutines a negative overhead abstraction gorn@microsoft.com
  • 2. What this talk is about? • C++ Coroutines • Lightweight, customizable coroutines • C++17 (maybe) • Experimental Implementation in MSVC 2015, Clang in progress, EDG 2012 - N3328 2013 - N3564 2013 - N3650 2013 - N3722 2014 - N3858 2014 - N3977 2014 - N4134 EWG direction approved 2014 - N4286 2015 - N4403 EWG accepted, sent to Core WG 2015 - P0057R0 Core & LEWG review (co_xxx) 2016 - P0057R2 more Core & LEWG review C++ Russia 2016 Coroutines 2
  • 3. C++ in two lines • Direct mapping to hardware • Zero-overhead abstractions C++ Russia 2016 Coroutines 3 From Bjarne Stroustrup lecture: The Essence of C++ Assembler BCPL C Simula C++ General-Purpose Abstractions C++11 C++14 Direct Mapping to hardware
  • 4. C++ Russia 2016 Coroutines 4
  • 5. C++ Russia 2016 Coroutines 5 000100 IDENTIFICATION DIVISION. 000200 PROGRAM-ID. HELLOWORLD. 000300* 000400 ENVIRONMENT DIVISION. 000500 CONFIGURATION SECTION. 000600 SOURCE-COMPUTER. RM-COBOL. 000700 OBJECT-COMPUTER. RM-COBOL. 000800 001000 DATA DIVISION. 001100 FILE SECTION. 001200 100000 PROCEDURE DIVISION. 100100 100200 MAIN-LOGIC SECTION. 100300 BEGIN. 100400 DISPLAY " " LINE 1 POSITION 1 ERASE EOS. 100500 DISPLAY "Hello world!" LINE 15 POSITION 10. 100600 STOP RUN. 100700 MAIN-LOGIC-EXIT. 100800 EXIT.
  • 6. C++ Russia 2016 Coroutines 6
  • 7. C++ Russia 2016 Coroutines 7
  • 8. C++ Russia 2016 Coroutines 8
  • 9. C++ Russia 2016 Coroutines 9
  • 10.  Joel Erdwinn Melvin Conway C++ Russia 2016 Coroutines 10 image credits: wikipedia commons, Communication of the ACM vol.6 No.7 July 1963
  • 11. C S Y A A C Y Write to Tape S A1 C Y2 Subroutine Coroutine Basic Symbol Reducer A C Basic Name Reducer A C S AS Y output token S A Basic Symbol Reducer S Y S Y S A C Y 1 2 S Y3 S A read token read token Subroutine Subroutine Subroutine SubroutineCoroutine C++ Russia 2016 Coroutines 11
  • 12. 100 cards per minute! C++ Russia 2016 Coroutines 12
  • 13. C++ Russia 2016 Coroutines 13
  • 14. Async state machine C++ Russia 2016 Coroutines 14 Failed Connecting Completed Reading
  • 15. Trivial if synchronous int tcp_reader(int total) { char buf[4 * 1024]; auto conn = Tcp::Connect("127.0.0.1", 1337); for (;;) { auto bytesRead = conn.Read(buf, sizeof(buf)); total -= bytesRead; if (total <= 0 || bytesRead == 0) return total; } } C++ Russia 2016 Coroutines 15
  • 16. std::future<T> and std::promise<T> shared_state<T> atomic<long> refCnt; mutex lock; variant<empty, T, exception_ptr> value; conditional_variable ready; future<T> intrusive_ptr<shared_state<T>> wait() T get() promise<T> intrusive_ptr<shared_state<T>> set_value(T) set_exception(exception_ptr) C++ Russia 2016 Coroutines 16
  • 17. future<int> tcp_reader(int64_t total) { struct State { char buf[4 * 1024]; int64_t total; Tcp::Connection conn; explicit State(int64_t total) : total(total) {} }; auto state = make_shared<State>(total); return Tcp::Connect("127.0.0.1", 1337).then( [state](future<Tcp::Connection> conn) { state->conn = std::move(conn.get()); return do_while([state]()->future<bool> { if (state->total <= 0) return make_ready_future(false); return state->conn.read(state->buf, sizeof(state->buf)).then( [state](future<int> nBytesFut) { auto nBytes = nBytesFut.get() if (nBytes == 0) return make_ready_future(false); state->total -= nBytes; return make_ready_future(true); }); }); }); } N4399 Working Draft, Technical Specification for C++ Extensions for Concurrency .then future<void> do_while(function<future<bool>()> body) { return body().then([=](future<bool> notDone) { return notDone.get() ? do_while(body) : make_ready_future(); }); } C++ Russia 2016 Coroutines 17
  • 18. Forgot something int tcp_reader(int total) { char buf[4 * 1024]; auto conn = Tcp::Connect("127.0.0.1", 1337); for (;;) { auto bytesRead = conn.Read(buf, sizeof(buf)); total -= bytesRead; if (total <= 0 || bytesRead == 0) return total; } } C++ Russia 2016 Coroutines 18
  • 19. future<int> tcp_reader(int64_t total) { struct State { char buf[4 * 1024]; int64_t total; Tcp::Connection conn; explicit State(int64_t total) : total(total) {} }; auto state = make_shared<State>(total); return Tcp::Connect("127.0.0.1", 1337).then( [state](future<Tcp::Connection> conn) { state->conn = std::move(conn.get()); return do_while([state]()->future<bool> { if (state->total <= 0) return make_ready_future(false); return state->conn.read(state->buf, sizeof(state->buf)).then( [state](future<int> nBytesFut) { auto nBytes = nBytesFut.get() if (nBytes == 0) return make_ready_future(false); state->total -= nBytes; return make_ready_future(true); }); // read }); // do_while }); // Tcp::Connect } .then C++ Russia 2016 Coroutines 19
  • 20. future<int> tcp_reader(int64_t total) { struct State { char buf[4 * 1024]; int64_t total; Tcp::Connection conn; explicit State(int64_t total) : total(total) {} }; auto state = make_shared<State>(total); return Tcp::Connect("127.0.0.1", 1337).then( [state](future<Tcp::Connection> conn) { state->conn = std::move(conn.get()); return do_while([state]()->future<bool> { if (state->total <= 0) return make_ready_future(false); return state->conn.read(state->buf, sizeof(state->buf)).then( [state](future<int> nBytesFut) { auto nBytes = nBytesFut.get() if (nBytes == 0) return make_ready_future(false); state->total -= nBytes; return make_ready_future(true); }); // read }); // do_while }).then([state](future<void>){return make_ready_future(state->total)}); } .then C++ Russia 2016 Coroutines 20
  • 21. C++ Russia 2016 Coroutines 21 Hand-crafted async state machine (1/3) class tcp_reader { char buf[64 * 1024]; Tcp::Connection conn; promise<int> done; int total; explicit tcp_reader(int total): total(total) {} void OnConnect(error_code ec, Tcp::Connection newCon); void OnRead(error_code ec, int bytesRead); void OnError(error_code ec); void OnComplete(); public: static future<int> start(int total); }; int main() { cout << tcp_reader::start(1000 * 1000 * 1000).get(); } Failed Connecting Completed Reading ① ① ② ② ③ ③ ④ ④ ⑤ ⑤
  • 22. Hand-crafted async state machine (2/3) C++ Russia 2016 Coroutines 22 future<int> tcp_reader::start(int total) { auto p = make_unique<tcp_reader>(total); auto result = p->done.get_future(); Tcp::Connect("127.0.0.1", 1337, [raw = p.get()](auto ec, auto newConn) { raw->OnConnect(ec, std::move(newConn)); }); p.release(); return result; } void tcp_reader::OnConnect(error_code ec, Tcp::Connection newCon) { if (ec) return OnError(ec); conn = std::move(newCon); conn.Read(buf, sizeof(buf), [this](error_code ec, int bytesRead) { OnRead(ec, bytesRead); }); }
  • 23. Hand-crafted async state machine (3/3) C++ Russia 2016 Coroutines 23 void tcp_reader::OnRead(error_code ec, int bytesRead) { if (ec) return OnError(ec); total -= bytesRead; if (total <= 0 || bytesRead == 0) return OnComplete(); conn.Read(buf, sizeof(buf), [this](error_code ec, int bytesRead) { OnRead(ec, bytesRead); }); } void OnError(error_code ec) { auto cleanMe = unique_ptr<tcp_reader>(this); done.set_exception(make_exception_ptr(system_error(ec))); } void OnComplete() { auto cleanMe = unique_ptr<tcp_reader>(this); done.set_value(total); }
  • 24. Async state machine C++ Russia 2016 Coroutines 24 Failed Connecting Completed Reading
  • 25. Trivial auto tcp_reader(int total) -> int { char buf[4 * 1024]; auto conn = Tcp::Connect("127.0.0.1", 1337); for (;;) { auto bytesRead = conn.Read(buf, sizeof(buf)); total -= bytesRead; if (total <= 0 || bytesRead == 0) return total; } } C++ Russia 2016 Coroutines 25
  • 26. Trivial auto tcp_reader(int total) -> future<int> { char buf[4 * 1024]; auto conn = await Tcp::Connect("127.0.0.1", 1337); for (;;) { auto bytesRead = await conn.Read(buf, sizeof(buf)); total -= bytesRead; if (total <= 0 || bytesRead == 0) return total; } } C++ Russia 2016 Coroutines 26
  • 27. What about perf? MB/s Binary size (Kbytes) Visual C++ 2015 RTM. Measured on Lenovo W540 laptop. Transmitting & Receiving 1GB over loopback IP addr C++ Russia 2016 Coroutines 27 495 (1.3x) 380 0 25 (0.85x) 30 9 Hand-CraftedCoroutines int main() { printf("Hello, worldn"); } Hello
  • 28. Coroutines are closer to the metal C++ Russia 2016 Coroutines 28 Hardware OS / Low Level Libraries Handcrafted State Machines I/O Abstractions (Callback based) I/O Abstraction (Awaitable based) Coroutines
  • 29. How to map high level call to OS API? C++ Russia 2016 Coroutines 29 template <class Cb> void Read(void* buf, size_t bytes, Cb && cb); conn.Read(buf, sizeof(buf), [this](error_code ec, int bytesRead) { OnRead(ec, bytesRead); }); Windows: WSARecv(fd, ..., OVERLAPPED*) Posix aio: aio_read(fd, ..., aiocbp*) aiocbp Function Object OVERLAPPED Function Object
  • 30. struct OverlappedBase : os_async_context { virtual void Invoke(std::error_code, int bytes) = 0; virtual ~OverlappedBase() {} static void io_complete_callback(CompletionPacket& p) { auto me = unique_ptr<OverlappedBase>(static_cast<OverlappedBase*>(p.overlapped)); me->Invoke(p.error, p.byteTransferred); } }; template <typename Fn> unique_ptr<OverlappedBase> make_handler_with_count(Fn && fn) { return std::make_unique<CompletionWithCount<std::decay_t<Fn>>(std::forward<Fn>(fn)); } os_async_ctx OVERLAPPED/aiocbp Function Object After open associate a socket handle with a threadpool and a callback ThreadPool::AssociateHandle(sock.native_handle(), &OverlappedBase::io_complete_callback); template <typename Fn> struct CompletionWithCount : OverlappedBase, private Fn { CompletionWithCount(Fn fn) : Fn(std::move(fn)) {} void Invoke(std::error_code ec, int count) override { Fn::operator()(ec, count); } }; C++ Russia 2016 Coroutines 30
  • 31. template <typename F> void Read(void* buf, int len, F && cb) { return Read(buf, len, make_handler_with_count(std::forward<F>(cb))); } void Read(void* buf, int len, std::unique_ptr<detail::OverlappedBase> o) { auto error = sock.Receive(buf, len, o.get()); if (error) { if (error.value() != kIoPending) { o->Invoke(error, 0); return; } } o.release(); } conn.Read(buf, sizeof(buf), [this](error_code ec, int bytesRead) { OnRead(ec, bytesRead); }); C++ Russia 2016 Coroutines 31
  • 32. await conn.Read(buf, sizeof(buf)); ? C++ Russia 2016 Coroutines 32
  • 33. Awaitable – Concept of the Future<T> C++ Russia 2016 Coroutines 33 .await_ready() F<T> → bool .await_suspend(cb) F<T> x Fn → void .await_resume() F<T> → T Present T Present T Present T await expr-of-awaitable-type
  • 34. await <expr> C++ Russia 2016 Coroutines Expands into an expression equivalent of { auto && tmp = operator await(opt) <expr>; if (!tmp.await_ready()) { tmp.await_suspend(<coroutine-handle>); } return tmp.await_resume(tmp); } suspend resume 34
  • 35. Overlapped Base from before struct OverlappedBase : os_async_context { virtual void Invoke(std::error_code, int bytes) = 0; virtual ~OverlappedBase() {} static void io_complete_callback(CompletionPacket& p) { auto me = static_cast<OverlappedBase*>(p.overlapped); auto cleanMe = unique_ptr<OverlappedBase>(me); me->Invoke(p.error, p.byteTransferred); } }; C++ Russia 2016 Coroutines 35
  • 36. Overlapped Base for awaitable struct AwaiterBase : os_async_context { coroutine_handle<> resume; std::error_code err; int bytes; static void io_complete_callback(CompletionPacket& p) { auto me = static_cast<AwaiterBase*>(p.overlapped); me->err = p.error; me->bytes = p.byteTransferred; me->resume(); } }; mov rcx, [rcx] jmp [rcx] sizeof(void*) no dtor C++ Russia 2016 Coroutines 36
  • 37. await conn.Read(buf, sizeof(buf)); ? C++ Russia 2016 Coroutines 37
  • 38. auto Connection::Read(void* buf, int len) { struct awaiter: AwaiterBase { Connection* me; void* buf; awaiter(Connection* me, void* buf, int len) : me(me), buf(buf) { bytes = len; } bool await_ready() { return false; } void await_suspend(coroutine_handle<> h) { this->resume = h; auto error = me->sock.Receive(buf, bytes, this); if (error.value() != kIoPending) throw system_error(err); } int await_resume() { if (this->err) throw system_error(err); return bytes; } }; return awaiter{ this, buf, len }; } C++ Russia 2016 Coroutines 38 struct AwaiterBase : os_async_context { coroutine_handle<> resume; std::error_code err; int bytes; static void io_complete_callback(CompletionPacket& p){ auto me = static_cast<AwaiterBase*>(p.overlapped); me->err = p.error; me->bytes = p.byteTransferred; me->resume(); } };
  • 39. Trivial auto tcp_reader(int total) -> future<int> { char buf[4 * 1024]; auto conn = await Tcp::Connect("127.0.0.1", 1337); for (;;) { auto bytesRead = await conn.Read(buf, sizeof(buf)); total -= bytesRead; if (total <= 0 || bytesRead == 0) return total; } } C++ Russia 2016 Coroutines 39
  • 40. Can we make it better? 50% I/O completes synchronously 50% I/O with I/O pending error C++ Russia 2016 Coroutines 40 SetFileCompletionNotificationModes(h, FILE_SKIP_COMPLETION_PORT_ON_SUCCESS);
  • 41. Take advantage of synchronous completions C++ Russia 2016 Coroutines 41 void Read(void* buf, int len, std::unique_ptr<detail::OverlappedBase> o) { auto error = sock.Receive(buf, len, o.get()); if (error) { if (error.value() != kIoPending) { o->Invoke(error, 0); return; } } o.release(); } SetFileCompletionNotificationModes(h, FILE_SKIP_COMPLETION_PORT_ON_SUCCESS);
  • 42. Take advantage of synchronous completions C++ Russia 2016 Coroutines 42 void Read(void* buf, int len, std::unique_ptr<detail::OverlappedBase> o) { auto error = sock.Receive(buf, len, o.get()); if (error.value() != kIoPending) { o->Invoke(error, len); return; } o.release(); } SetFileCompletionNotificationModes(h, FILE_SKIP_COMPLETION_PORT_ON_SUCCESS);
  • 43. Take advantage of synchronous completions C++ Russia 2016 Coroutines 43 void Read(void* buf, int len, std::unique_ptr<detail::OverlappedBase> o) { auto error = sock.Receive(buf, len, o.get()); if (error.value() != kIoPending) { o->Invoke(error, len); return; } o.release(); } SetFileCompletionNotificationModes(h, FILE_SKIP_COMPLETION_PORT_ON_SUCCESS); SuperLean.exe!improved::tcp_reader::OnRead(std::error_code ec, int bytesRead) Line 254 SuperLean.exe!improved::detail::CompletionWithSizeT<<lambda_ee38b7a750c7f550b4ee1dd60c2450c1> >::Invoke(std::error_code ec, int count) Line 31 SuperLean.exe!improved::tcp_reader::OnRead(std::error_code ec, int bytesRead) Line 254 SuperLean.exe!improved::detail::CompletionWithSizeT<<lambda_ee38b7a750c7f550b4ee1dd60c2450c1> >::Invoke(std::error_code ec, int count) Line 31 SuperLean.exe!improved::tcp_reader::OnRead(std::error_code ec, int bytesRead) Line 254 SuperLean.exe!improved::detail::CompletionWithSizeT<<lambda_ee38b7a750c7f550b4ee1dd60c2450c1> >::Invoke(std::error_code ec, int count) Line 31 SuperLean.exe!improved::tcp_reader::OnRead(std::error_code ec, int bytesRead) Line 254 SuperLean.exe!improved::detail::CompletionWithSizeT<<lambda_ee38b7a750c7f550b4ee1dd60c2450c1> >::Invoke(std::error_code ec, int count) Line 31 SuperLean.exe!improved::tcp_reader::OnRead(std::error_code ec, int bytesRead) Line 254 SuperLean.exe!improved::detail::CompletionWithSizeT<<lambda_ee38b7a750c7f550b4ee1dd60c2450c1> >::Invoke(std::error_code ec, int count) Line 31 SuperLean.exe!improved::tcp_reader::OnRead(std::error_code ec, int bytesRead) Line 254 SuperLean.exe!improved::detail::CompletionWithSizeT<<lambda_ee38b7a750c7f550b4ee1dd60c2450c1> >::Invoke(std::error_code ec, int count) Line 31 SuperLean.exe!improved::tcp_reader::OnRead(std::error_code ec, int bytesRead) Line 254 SuperLean.exe!improved::detail::CompletionWithSizeT<<lambda_ee38b7a750c7f550b4ee1dd60c2450c1> >::Invoke(std::error_code ec, int count) Line 31 SuperLean.exe!improved::tcp_reader::OnRead(std::error_code ec, int bytesRead) Line 254 SuperLean.exe!improved::detail::CompletionWithSizeT<<lambda_ee38b7a750c7f550b4ee1dd60c2450c1> >::Invoke(std::error_code ec, int count) Line 31 SuperLean.exe!improved::tcp_reader::OnRead(std::error_code ec, int bytesRead) Line 254 SuperLean.exe!improved::detail::CompletionWithSizeT<<lambda_ee38b7a750c7f550b4ee1dd60c2450c1> >::Invoke(std::error_code ec, int count) Line 31 SuperLean.exe!improved::tcp_reader::OnRead(std::error_code ec, int bytesRead) Line 254 SuperLean.exe!improved::detail::CompletionWithSizeT<<lambda_ee38b7a750c7f550b4ee1dd60c2450c1> >::Invoke(std::error_code ec, int count) Line 31 SuperLean.exe!improved::tcp_reader::OnRead(std::error_code ec, int bytesRead) Line 254 SuperLean.exe!improved::detail::CompletionWithSizeT<<lambda_ee38b7a750c7f550b4ee1dd60c2450c1> >::Invoke(std::error_code ec, int count) Line 31 SuperLean.exe!improved::tcp_reader::OnRead(std::error_code ec, int bytesRead) Line 254 SuperLean.exe!improved::detail::CompletionWithSizeT<<lambda_ee38b7a750c7f550b4ee1dd60c2450c1> >::Invoke(std::error_code ec, int count) Line 31 SuperLean.exe!improved::tcp_reader::OnRead(std::error_code ec, int bytesRead) Line 254 SuperLean.exe!improved::detail::CompletionWithSizeT<<lambda_ee38b7a750c7f550b4ee1dd60c2450c1> >::Invoke(std::error_code ec, int count) Line 31 SuperLean.exe!improved::tcp_reader::OnRead(std::error_code ec, int bytesRead) Line 254 SuperLean.exe!improved::detail::CompletionWithSizeT<<lambda_ee38b7a750c7f550b4ee1dd60c2450c1> >::Invoke(std::error_code ec, int count) Line 31 SuperLean.exe!improved::tcp_reader::OnRead(std::error_code ec, int bytesRead) Line 254 SuperLean.exe!improved::detail::CompletionWithSizeT<<lambda_ee38b7a750c7f550b4ee1dd60c2450c1> >::Invoke(std::error_code ec, int count) Line 31 SuperLean.exe!improved::tcp_reader::OnRead(std::error_code ec, int bytesRead) Line 254 SuperLean.exe!improved::detail::CompletionWithSizeT<<lambda_ee38b7a750c7f550b4ee1dd60c2450c1> >::Invoke(std::error_code ec, int count) Line 31 SuperLean.exe!improved::detail::io_complete_callback(CompletionPacket & p) Line 22 SuperLean.exe!CompletionQueue::ThreadProc(void * lpParameter) Line 112 C++ Stack Overflow
  • 44. Need to implement it on the use side C++ Russia 2016 Coroutines 44 void tcp_reader::OnRead(std::error_code ec, int bytesRead) { if (ec) return OnError(ec); total -= (int)bytesRead; if (total <= 0 || bytesRead == 0) return OnComplete(); bytesRead = sizeof(buf); conn.Read(buf, bytesRead, [this](std::error_code ec, int bytesRead) { OnRead(ec, bytesRead); }) ; }
  • 45. Now handling synchronous completion C++ Russia 2016 Coroutines 45 void tcp_reader::OnRead(std::error_code ec, int bytesRead) { do { if (ec) return OnError(ec); total -= (int)bytesRead; if (total <= 0 || bytesRead == 0) return OnComplete(); bytesRead = sizeof(buf); } while ( conn.Read(buf, bytesRead, [this](std::error_code ec, int bytesRead) { OnRead(ec, bytesRead); })); }
  • 46. Let’s measure the improvement (handwritten) C++ Russia 2016 Coroutines 46 Handcrafted Coroutine Handcrafted Coroutine Original 380 495 30 25 Synchr Completion. Opt MB/s Executable size 485 25 30
  • 47. auto Connection::Read(void* buf, int len) { struct awaiter: AwaiterBase { Connection* me; void* buf; awaiter(Connection* me, void* buf, int len) : me(me), buf(buf) { bytes = len; } bool await_ready() { return false; } void await_suspend(coroutine_handle<> h) { this->resume = h; auto error = me->sock.Receive(buf, bytes, this); if (error.value() == kIoPending) return; if (error) throw system_error(err); return; } int await_resume() { if (this->err) throw system_error(err); return bytes; } }; return awaiter{ this, buf, len }; } C++ Russia 2016 Coroutines 47 struct AwaiterBase : os_async_context { coroutine_handle<> resume; std::error_code err; int bytes; static void io_complete_callback(CompletionPacket& p){ auto me = static_cast<AwaiterBase*>(p.overlapped); me->err = p.error; me->bytes = p.byteTransferred; me->resume(); } }; SetFileCompletionNotificationModes(h, FILE_SKIP_COMPLETION_PORT_ON_SUCCESS);
  • 48. auto Connection::Read(void* buf, int len) { struct awaiter: AwaiterBase { Connection* me; void* buf; awaiter(Connection* me, void* buf, int len) : me(me), buf(buf) { bytes = len; } bool await_ready() { return false; } bool await_suspend(coroutine_handle<> h) { this->resume = h; auto error = me->sock.Receive(buf, bytes, this); if (error.value() == kIoPending) return true; if (error) throw system_error(err); return false; } int await_resume() { if (this->err) throw system_error(err); return bytes; } }; return awaiter{ this, buf, len }; } C++ Russia 2016 Coroutines 48 struct AwaiterBase : os_async_context { coroutine_handle<> resume; std::error_code err; int bytes; static void io_complete_callback(CompletionPacket& p){ auto me = static_cast<AwaiterBase*>(p.overlapped); me->err = p.error; me->bytes = p.byteTransferred; me->resume(); } };
  • 49. await <expr> C++ Russia 2016 Coroutines Expands into an expression equivalent of { auto && tmp = operator co_await <expr>; if (! tmp.await_ready()) { tmp.await_suspend(<coroutine-handle>); } return tmp.await_resume(); } suspend resume 49
  • 50. await <expr> C++ Russia 2016 Coroutines Expands into an expression equivalent of { auto && tmp = operator await(opt) <expr>; if (! tmp.await_ready() && tmp.await_suspend(<coroutine-handle>) { } return tmp.await_resume(); } suspend resume 50
  • 51. Let’s measure the improvement (coroutine) C++ Russia 2016 Coroutines 51 Handcrafted Coroutine Handcrafted Coroutine Original 380 495 30 25 Synchr Completion. Opt 485 30 MB/s Executable size 1028 25 25
  • 52. Can we make it better? C++ Russia 2016 Coroutines 53
  • 53. Getting rid of the allocations C++ Russia 2016 Coroutines 54 class tcp_reader { std::unique_ptr<detail::OverlappedBase> wo; … tcp_reader(int64_t total) : total(total) { wo = detail::make_handler_with_count( [this](auto ec, int nBytes) {OnRead(ec, nBytes); }); … } void OnRead(std::error_code ec, int bytesRead) { if (ec) return OnError(ec); do { total -= (int)bytesRead; if (total <= 0 || bytesRead == 0) return OnComplete(); bytesRead = sizeof(buf); } while (conn.Read(buf, bytesRead, wo.get())); }
  • 54. Let’s measure the improvement (handcrafted) C++ Russia 2016 Coroutines 55 Handcrafted Coroutine Handcrafted Coroutine Original 380 495 30 25 Synchr Completion. Opt 485 1028 30 25 Prealloc handler 1028 25 MB/s Executable size 690 25 28
  • 55. Coroutines are popular! Python: PEP 0492 async def abinary(n): if n <= 0: return 1 l = await abinary(n - 1) r = await abinary(n - 1) return l + 1 + r HACK (programming language) async function gen1(): Awaitable<int> { $x = await Batcher::fetch(1); $y = await Batcher::fetch(2); return $x + $y; } DART 1.9 Future<int> getPage(t) async { var c = new http.Client(); try { var r = await c.get('http://url/search?q=$t'); print(r); return r.length(); } finally { await c.close(); } } C# async Task<string> WaitAsynchronouslyAsync() { await Task.Delay(10000); return "Finished"; } C++17 future<string> WaitAsynchronouslyAsync() { await sleep_for(10ms); return "Finished“s; } C++ Russia 2016 Coroutines 56
  • 56. Cosmetics (Nov 2015, keyword change) co_await co_yield co_return C++ Russia 2016 Coroutines 57
  • 57. Generalized Function C++ Russia 2016 Coroutines 58 Compiler User Coroutine Designer Async Generator await + yield Generator yield Task await Monadic* await - suspend POF does not careimage credits: Три богатыря и змей горыныч
  • 58. Design Principles • Scalable (to billions of concurrent coroutines) • Efficient (resume and suspend operations comparable in cost to a function call overhead) • Seamless interaction with existing facilities with no overhead • Open ended coroutine machinery allowing library designers to develop coroutine libraries exposing various high-level semantics, such as generators, goroutines, tasks and more. • Usable in environments where exceptions are forbidden or not available 59C++ Russia 2016 Coroutines
  • 59. C++ Russia 2016 Coroutines 60
  • 61. C++ Russia 2016 Coroutines 64 Return Address Locals of F Parameters of F Thread Stack F’s Activation Record … Return Address Locals of G Parameters of G G’s Activation Record Return Address Locals of H Parameters of H H’s Activation Record Stack Pointer Stack Pointer Stack Pointer Normal Functions
  • 62. C++ Russia 2016 Coroutines 65 Return Address Locals of F Parameters of F Thread 1 Stack F’s Activation Record … Return Address Locals of G Parameters of G G’s Activation Record Return Address Locals of H Parameters of H H’s Activation Record Stack Pointer Stack Pointer Stack Pointer Normal Functions
  • 63. C++ Russia 2016 Coroutines 66 Return Address Locals of F Parameters of F Thread 1 Stack F’s Activation Record … Return Address Locals of H Parameters of H H’s Activation Record Stack Pointer Coroutines using Fibers (first call) Stack Pointer Locals of G Parameters of G Return Address Fiber Context Old Stack Top Saved Registers Fiber Stack Fiber Start Routine Thread Context: IP,RSP,RAX,RCX RDX,… RDI, etc Saved Registers
  • 64. C++ Russia 2016 Coroutines 67 Return Address Locals of F Parameters of F Thread 1 Stack F’s Activation Record … Return Address Locals of H Parameters of H H’s Activation Record Coroutines using Fibers (Suspend) Stack Pointer Locals of G Parameters of G Return Address Fiber Context Old Stack Top Saved Registers Fiber Stack Fiber Start Routine Thread Context: IP,RSP,RAX,RCX RDX,… RDI,RSI, etc Saved RegistersSaved Registers
  • 65. C++ Russia 2016 Coroutines 68 Return Address Locals of Z Parameters of Z Thread 2 Stack Z’s Activation Record … Return Address Locals of H Parameters of H H’s Activation Record Stack Pointer Coroutines using Fibers (Resume) Locals of G Parameters of G Return Address Fiber Context Old Stack Top Saved Registers Fiber Stack Fiber Start Routine Saved Registers Return Address Saved Registers
  • 68. Mitigating Memory Footprint Fiber State 1 meg of stack (chained stack) 4k stacklet 4k stacklet 4k stacklet 4k stacklet … 4k stacklet C++ Russia 2016 Coroutines 71 (reallocate and copy) 2k stack 4k stack … 1k stack 8k stack 16k stack
  • 69. Design Principles • Scalable (to billions of concurrent coroutines) • Efficient (resume and suspend operations comparable in cost to a function call overhead) • Seamless interaction with existing facilities with no overhead • Open ended coroutine machinery allowing library designers to develop coroutine libraries exposing various high-level semantics, such as generators, goroutines, tasks and more. • Usable in environments where exceptions are forbidden or not available 72C++ Russia 2016 Coroutines
  • 70. Compiler based coroutines C++ Russia 2016 Coroutines 73 generator<int> f() { for (int i = 0; i < 5; ++i) { yield i; } generator<int> f() { f$state *mem = __coro_elide() ? alloca(f$state) : new f$state; mem->__resume_fn = &f$resume; mem->__destroy_fn = &f$resume; return {mem}; } struct f$state { void* __resume_fn; void* __destroy_fn; int __resume_index = 0; int i; }; void f$resume(f$state s) { switch (s->__resume_index) { case 0: s->i = 0; s->resume_index = 1; break; case 1: if( ++s->i == 5) s->resume_address = nullptr; break; } } int main() { for (int v: f()) printf(“%dn”, v); } void f$destroy(f$state s) { if(!__coro_elide()) delete f$state; } int main() { printf(“%dn”, 0); printf(“%dn”, 1); printf(“%dn”, 2); printf(“%dn”, 3); printf(“%dn”, 4); }
  • 71. C++ Russia 2016 Coroutines 74 Return Address Locals of F Parameters of F Thread 1 Stack F’s Activation Record … Return Address Locals of G Parameters of G G’s Activation Record (Coroutine) Return Address Locals of H Parameters of H H’s Activation Record Stack Pointer Stack Pointer Stack Pointer Compiler Based Coroutines struct G$state { void* __resume_fn; void* __destroy_fn; int __resume_index; locals, temporaries that need to preserve values across suspend points }; G’s Coroutine State
  • 72. C++ Russia 2016 Coroutines 75 Return Address Locals of F Parameters of F Thread 1 Stack F’s Activation Record … Return Address Locals of G Parameters of G G’s Activation Record Return Address Locals of H Parameters of H H’s Activation Record Stack Pointer Stack Pointer Stack Pointer Compiler Based Coroutines (Suspend) struct G$state { void* __resume_fn; void* __destroy_fn; int __resume_index; locals, temporaries that need to preserve values across suspend points }; G’s Coroutine State
  • 73. C++ Russia 2016 Coroutines 76 Return Address Locals of X Parameters of X Thread 2 Stack X’s Activation Record … Return Address Locals of g$resume Parameters of g$resume G$resume’s Activation Record Return Address Locals of H Parameters of H H’s Activation Record Stack Pointer Stack Pointer Stack Pointer Compiler Based Coroutines (Resume) struct G$state { void* __resume_fn; void* __destroy_fn; int __resume_index; locals, temporaries that need to preserve values across suspend points }; G’s Coroutine State
  • 74. Design Principles • Scalable (to billions of concurrent coroutines) • Efficient (resume and suspend operations comparable in cost to a function call overhead) • Seamless interaction with existing facilities with no overhead • Open ended coroutine machinery allowing library designers to develop coroutine libraries exposing various high-level semantics, such as generators, goroutines, tasks and more. • Usable in environments where exceptions are forbidden or not available 77C++ Russia 2016 Coroutines
  • 75. 2 x 2 x 2 • Two new keywords •await •yield syntactic sugar for: await $p.yield_value(expr) • Two new concepts •Awaitable •Coroutine Promise •Two library types • coroutine_handle • coroutine_traits C++ Russia 2016 Coroutines 79 After Kona 2015 co_await co_yield co_return
  • 76. Trivial Awaitable #1 C++ Russia 2016 Coroutines 80 struct _____blank____ { bool await_ready(){ return false; } template <typename F> void await_suspend(F){} void await_resume(){} };
  • 77. Trivial Awaitable #1 C++ Russia 2016 Coroutines 81 struct suspend_always { bool await_ready(){ return false; } template <typename F> void await_suspend(F){} void await_resume(){} }; await suspend_always {};
  • 78. Trivial Awaitable #2 C++ Russia 2016 Coroutines 82 struct suspend_never { bool await_ready(){ return true; } template <typename F> void await_suspend(F){} void await_resume(){} };
  • 79. Simple Awaitable #1 C++ Russia 2016 Coroutines 83 std::future<void> DoSomething(mutex& m) { unique_lock<mutex> lock = await lock_or_suspend{m}; // ... } struct lock_or_suspend { std::unique_lock<std::mutex> lock; lock_or_suspend(std::mutex & mut) : lock(mut, std::try_to_lock) {} bool await_ready() { return lock.owns_lock(); } template <typename F> void await_suspend(F cb) { std::thread t([this, cb]{ lock.lock(); cb(); }); t.detach(); } auto await_resume() { return std::move(lock);} };
  • 80. Awaitable Interacting with C APIs C++ Russia 2016 Coroutines 84
  • 81. 2 x 2 x 2 • Two new keywords •await •yield syntactic sugar for: await $p.yield_value(expr) • Two new concepts •Awaitable •Coroutine Promise •Two library types • coroutine_handle • coroutine_traits C++ Russia 2016 Coroutines 85 After Kona 2015 co_await co_yield co_return
  • 82. coroutine_handle C++ Russia 2016 Coroutines 86 template <typename Promise = void> struct coroutine_handle; template <> struct coroutine_handle<void> { void resume(); void destroy(); bool done() const; void * address(); static coroutine_handle from_address(void*); void operator()(); // same as resume() … }; == != < > <= >=
  • 83. Simple Awaitable #2: Raw OS APIs await 10ms; C++ Russia 2016 Coroutines 87 class awaiter { static void CALLBACK TimerCallback(PTP_CALLBACK_INSTANCE, void *Context, PTP_TIMER) { std::experimental::coroutine_handle<>::from_address(Context).resume(); } PTP_TIMER timer = nullptr; std::chrono::system_clock::duration duration; public: explicit awaiter(std::chrono::system_clock::duration d) : duration(d) {} bool await_ready() const { return duration.count() <= 0; } void await_suspend(std::experimental::coroutine_handle<> resume_cb) { timer = CreateThreadpoolTimer(TimerCallback, resume_cb.address(), nullptr); if (!timer) throw std::bad_alloc(); int64_t relative_count = -duration.count(); SetThreadpoolTimer(timer, (PFILETIME)&relative_count, 0, 0); } void await_resume() {} ~awaiter() { if (timer) CloseThreadpoolTimer(timer); } }; auto operator await(std::chrono::system_clock::duration duration) { return awaiter{duration}; }
  • 84. 2 x 2 x 2 • Two new keywords •await •yield syntactic sugar for: await $p.yield_value(expr) • Two new concepts •Awaitable •Coroutine Promise •Two library types • coroutine_handle • coroutine_traits C++ Russia 2016 Coroutines 88 After Kona 2015 co_await co_yield co_return
  • 85. coroutine_traits C++ Russia 2016 Coroutines 89 template <typename R, typename... Ts> struct coroutine_traits { using promise_type = typename R::promise_type; }; generator<int> fib(int n) std::coroutine_traits<generator<int>, int>
  • 86. Compiler vs Coroutine Promise yield <expr> await <Promise>.yield_value(<expr>) <before-last-curly> return <expr> <Promise>.return_value(<expr>); goto <end> <after-first-curly> <unhandled-exception> <Promise>.set_exception ( std::current_exception()) <get-return-object> <Promise>.get_return_object() await <Promise>.initial_suspend() await <Promise>.final_suspend() C++ Russia 2016 Coroutines 90 await <expr> Spent the last hour talking about it <allocate coro-state> <Promise>.operator new (or global) <free coro-state> <Promise>.operator delete (or global)
  • 87. Defining Coroutine Promise for boost::future namespace std { template <typename T, typename… anything> struct coroutine_traits<boost::unique_future<T>, anything…> { struct promise_type { boost::promise<T> promise; auto get_return_object() { return promise.get_future(); } template <class U> void return_value(U && value) { promise.set_value(std::forward<U>(value)); } void set_exception(std::exception_ptr e) { promise.set_exception(std::move(e)); } std::suspend_never initial_suspend() { return {}; } std::suspend_never final_suspend() { return {}; } }; }; } C++ Russia 2016 Coroutines 91
  • 88. coroutine_handle<promise> C++ Russia 2016 Coroutines 92 template <typename Promise = void> struct coroutine_handle; template <> struct coroutine_handle<void> { void resume(); void destroy(); bool done() const; void * address(); static coroutine_handle from_address(void*); void operator()(); // same as resume() … }; template < typename Promise> struct coroutine_handle: coroutine_handle<void> { Promise & promise(); static coroutine_handle from_promise(Promise&); }; == != < > <= >=
  • 89. Defining Generator From Scratch C++ Russia 2016 Coroutines 93 struct int_generator { bool move_next(); int current_value(); … }; int_generator f() { for (int i = 0; i < 5; i++) { yield i; } int main() { auto g = f (); while (g.move_next()) { printf("%dn", g.current_value()); } }
  • 90. C++ Russia 2016 Coroutines 94 struct int_generator { struct promise_type { int current_value; std::suspend_always yield_value(int value) { this->current_value = value; return{}; } std::suspend_always initial_suspend() { return{}; } std::suspend_always final_suspend() { return{}; } int_generator get_return_object() { return int_generator{ this }; }; }; bool move_next() { p.resume(); return !p.done(); } int current_value() { return p.promise().current_value; } ~int_generator() { p.destroy(); } private: explicit int_generator(promise_type *p) : p(std::coroutine_handle<promise_type>::from_promise(*p)) {} std::coroutine_handle<promise_type> p; }; Defining Generator From Scratch yield <expr> await <Promise>.yield_value(<expr>)
  • 91. C++ Russia 2016 Coroutines 95 STL looks like the machine language macro library of an anally retentive assembly language programmer Pamela Seymour, Leiden University
  • 92. C++ Coroutines: Layered complexity • Everybody • Safe by default, novice friendly Use coroutines and awaitables defined by standard library, boost and other high quality libraries • Power Users • Define new awaitables to customize await for their environment using existing coroutine types • Experts • Define new coroutine types C++ Russia 2016 Coroutines 96
  • 93. Thank you! C++ Russia 2016 Coroutines 97 Kavya Kotacherry, Daveed Vandevoorde, Richard Smith, Jens Maurer, Lewis Baker, Kirk Shoop, Hartmut Kaiser, Kenny Kerr, Artur Laksberg, Jim Radigan, Chandler Carruth, Gabriel Dos Reis, Deon Brewis, Jonathan Caves, James McNellis, Stephan T. Lavavej, Herb Sutter, Pablo Halpern, Robert Schumacher, Viktor Tong, Geoffrey Romer, Michael Wong, Niklas Gustafsson, Nick Maliwacki, Vladimir Petter, Shahms King, Slava Kuznetsov, Tongari J, Lawrence Crowl, Valentin Isac and many more who contributed
  • 94. Coroutines – a negative overhead abstraction C++ Russia 2016 Coroutines 98 • Proposal is working through C++ standardization committee (C++17?) • Experimental implementation in VS 2015 RTM • Clang implementation is in progress • more details: • http://www.open- std.org/JTC1/SC22/WG21/docs/papers/2016/P0057R2.pdf
  • 95. Questions? C++ Russia 2016 Coroutines 99