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

Inside Android's UI
Inside Android's UIInside Android's UI
Inside Android's UIOpersys inc.
 
NDC 2017 하재승 NEXON ZERO (넥슨 제로) 점검없이 실시간으로 코드 수정 및 게임 정보 수집하기
NDC 2017 하재승 NEXON ZERO (넥슨 제로) 점검없이 실시간으로 코드 수정 및 게임 정보 수집하기NDC 2017 하재승 NEXON ZERO (넥슨 제로) 점검없이 실시간으로 코드 수정 및 게임 정보 수집하기
NDC 2017 하재승 NEXON ZERO (넥슨 제로) 점검없이 실시간으로 코드 수정 및 게임 정보 수집하기Jaeseung Ha
 
Fondamentaux d’une API REST
Fondamentaux d’une API RESTFondamentaux d’une API REST
Fondamentaux d’une API RESTAbdoulaye Dieng
 
Microservices Meetup San Francisco - August 2017 Talk on NATS
Microservices Meetup San Francisco - August 2017 Talk on NATSMicroservices Meetup San Francisco - August 2017 Talk on NATS
Microservices Meetup San Francisco - August 2017 Talk on NATSNATS
 
44CON London - Attacking VxWorks: from Stone Age to Interstellar
44CON London - Attacking VxWorks: from Stone Age to Interstellar44CON London - Attacking VxWorks: from Stone Age to Interstellar
44CON London - Attacking VxWorks: from Stone Age to Interstellar44CON
 
C++20에서 리플렉션 기능 구현
C++20에서 리플렉션 기능 구현C++20에서 리플렉션 기능 구현
C++20에서 리플렉션 기능 구현Bongseok Cho
 
OWASP AppSecCali 2015 - Marshalling Pickles
OWASP AppSecCali 2015 - Marshalling PicklesOWASP AppSecCali 2015 - Marshalling Pickles
OWASP AppSecCali 2015 - Marshalling PicklesChristopher Frohoff
 
Cours java avance avancé thread arraylist
Cours java avance avancé thread arraylistCours java avance avancé thread arraylist
Cours java avance avancé thread arraylistHoussem Hamrouni
 
win32 app에서 UWP API호출하기
win32 app에서 UWP API호출하기win32 app에서 UWP API호출하기
win32 app에서 UWP API호출하기YEONG-CHEON YOU
 
Appalications JEE avec Servlet/JSP
Appalications JEE avec Servlet/JSPAppalications JEE avec Servlet/JSP
Appalications JEE avec Servlet/JSPYouness Boukouchi
 
Architectures microservices
Architectures microservicesArchitectures microservices
Architectures microservicesRiadh MNASRI
 
Hands on with CoAP and Californium
Hands on with CoAP and CaliforniumHands on with CoAP and Californium
Hands on with CoAP and CaliforniumJulien Vermillard
 
How to build massive service for advance
How to build massive service for advanceHow to build massive service for advance
How to build massive service for advanceDaeMyung Kang
 
Troubleshooting common oslo.messaging and RabbitMQ issues
Troubleshooting common oslo.messaging and RabbitMQ issuesTroubleshooting common oslo.messaging and RabbitMQ issues
Troubleshooting common oslo.messaging and RabbitMQ issuesMichael Klishin
 
Implementation &amp; Comparison Of Rdma Over Ethernet
Implementation &amp; Comparison Of Rdma Over EthernetImplementation &amp; Comparison Of Rdma Over Ethernet
Implementation &amp; Comparison Of Rdma Over EthernetJames Wernicke
 
[IGC 2017] 아마존 구승모 - 게임 엔진으로 서버 제작 및 운영까지
[IGC 2017] 아마존 구승모 - 게임 엔진으로 서버 제작 및 운영까지[IGC 2017] 아마존 구승모 - 게임 엔진으로 서버 제작 및 운영까지
[IGC 2017] 아마존 구승모 - 게임 엔진으로 서버 제작 및 운영까지강 민우
 
REST API and CRUD
REST API and CRUDREST API and CRUD
REST API and CRUDPrem Sanil
 

What's hot (20)

Inside Android's UI
Inside Android's UIInside Android's UI
Inside Android's UI
 
NDC 2017 하재승 NEXON ZERO (넥슨 제로) 점검없이 실시간으로 코드 수정 및 게임 정보 수집하기
NDC 2017 하재승 NEXON ZERO (넥슨 제로) 점검없이 실시간으로 코드 수정 및 게임 정보 수집하기NDC 2017 하재승 NEXON ZERO (넥슨 제로) 점검없이 실시간으로 코드 수정 및 게임 정보 수집하기
NDC 2017 하재승 NEXON ZERO (넥슨 제로) 점검없이 실시간으로 코드 수정 및 게임 정보 수집하기
 
Fondamentaux d’une API REST
Fondamentaux d’une API RESTFondamentaux d’une API REST
Fondamentaux d’une API REST
 
Introduction to JavaScript Basics.
Introduction to JavaScript Basics.Introduction to JavaScript Basics.
Introduction to JavaScript Basics.
 
Microservices Meetup San Francisco - August 2017 Talk on NATS
Microservices Meetup San Francisco - August 2017 Talk on NATSMicroservices Meetup San Francisco - August 2017 Talk on NATS
Microservices Meetup San Francisco - August 2017 Talk on NATS
 
44CON London - Attacking VxWorks: from Stone Age to Interstellar
44CON London - Attacking VxWorks: from Stone Age to Interstellar44CON London - Attacking VxWorks: from Stone Age to Interstellar
44CON London - Attacking VxWorks: from Stone Age to Interstellar
 
C++20에서 리플렉션 기능 구현
C++20에서 리플렉션 기능 구현C++20에서 리플렉션 기능 구현
C++20에서 리플렉션 기능 구현
 
OWASP AppSecCali 2015 - Marshalling Pickles
OWASP AppSecCali 2015 - Marshalling PicklesOWASP AppSecCali 2015 - Marshalling Pickles
OWASP AppSecCali 2015 - Marshalling Pickles
 
Building microservices with grpc
Building microservices with grpcBuilding microservices with grpc
Building microservices with grpc
 
Node js Introduction
Node js IntroductionNode js Introduction
Node js Introduction
 
Cours java avance avancé thread arraylist
Cours java avance avancé thread arraylistCours java avance avancé thread arraylist
Cours java avance avancé thread arraylist
 
win32 app에서 UWP API호출하기
win32 app에서 UWP API호출하기win32 app에서 UWP API호출하기
win32 app에서 UWP API호출하기
 
Appalications JEE avec Servlet/JSP
Appalications JEE avec Servlet/JSPAppalications JEE avec Servlet/JSP
Appalications JEE avec Servlet/JSP
 
Architectures microservices
Architectures microservicesArchitectures microservices
Architectures microservices
 
Hands on with CoAP and Californium
Hands on with CoAP and CaliforniumHands on with CoAP and Californium
Hands on with CoAP and Californium
 
How to build massive service for advance
How to build massive service for advanceHow to build massive service for advance
How to build massive service for advance
 
Troubleshooting common oslo.messaging and RabbitMQ issues
Troubleshooting common oslo.messaging and RabbitMQ issuesTroubleshooting common oslo.messaging and RabbitMQ issues
Troubleshooting common oslo.messaging and RabbitMQ issues
 
Implementation &amp; Comparison Of Rdma Over Ethernet
Implementation &amp; Comparison Of Rdma Over EthernetImplementation &amp; Comparison Of Rdma Over Ethernet
Implementation &amp; Comparison Of Rdma Over Ethernet
 
[IGC 2017] 아마존 구승모 - 게임 엔진으로 서버 제작 및 운영까지
[IGC 2017] 아마존 구승모 - 게임 엔진으로 서버 제작 및 운영까지[IGC 2017] 아마존 구승모 - 게임 엔진으로 서버 제작 및 운영까지
[IGC 2017] 아마존 구승모 - 게임 엔진으로 서버 제작 및 운영까지
 
REST API and CRUD
REST API and CRUDREST API and CRUD
REST API and CRUD
 

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

Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureDinusha Kumarasiri
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEOrtus Solutions, Corp
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaHanief Utama
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEEVICTOR MAESTRE RAMIREZ
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...OnePlan Solutions
 
chapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptchapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptkotipi9215
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantAxelRicardoTrocheRiq
 
Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)Hr365.us smith
 
The Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfThe Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfPower Karaoke
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software DevelopersVinodh Ram
 
Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Velvetech LLC
 
Unveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesUnveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesŁukasz Chruściel
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideChristina Lin
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...Christina Lin
 
英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作qr0udbr0
 
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024StefanoLambiase
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)OPEN KNOWLEDGE GmbH
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio, Inc.
 
What are the key points to focus on before starting to learn ETL Development....
What are the key points to focus on before starting to learn ETL Development....What are the key points to focus on before starting to learn ETL Development....
What are the key points to focus on before starting to learn ETL Development....kzayra69
 

Recently uploaded (20)

Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with Azure
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief Utama
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEE
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...
 
chapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptchapter--4-software-project-planning.ppt
chapter--4-software-project-planning.ppt
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service Consultant
 
Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)
 
The Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfThe Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdf
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software Developers
 
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort ServiceHot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
 
Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...
 
Unveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesUnveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New Features
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
 
英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作
 
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
 
What are the key points to focus on before starting to learn ETL Development....
What are the key points to focus on before starting to learn ETL Development....What are the key points to focus on before starting to learn ETL Development....
What are the key points to focus on before starting to learn ETL Development....
 

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