130 likes | 331 Views
C++ await Deon Brewis. std :: future additions: isocpp.org/files/papers/N3721.pdf resumable functions : isocpp.org/files/papers/N3722.pdf. PPL vs. std ::future. Requires future.then – i.e. N3721. PPL. std ::future. concurrency::task< int > Calc ( int x, int y ) resumable {
E N D
C++ awaitDeon Brewis std::future additions: isocpp.org/files/papers/N3721.pdf resumable functions: isocpp.org/files/papers/N3722.pdf
PPL vs. std::future Requires future.then – i.e. N3721 PPL std::future concurrency::task<int> Calc( int x, int y ) resumable { inti = awaitconcurrency::create_task( [=] { return x + y; } ); returni + 42; } std::future<int> Calc( int x, int y ) resumable { inti = awaitstd::async( [=] { return x + y; } ); returni+ 42; }
Simple case .get size_tfile_sizes( string file1, string file2 ) { task<file> f1 = open(file1); task<file> f2 = open(file2); return f1.get().size() + f2.get().size(); }
Simple case .get .then task<size_t> file_sizes( string file1, string file2 ) { task<file> f1 = open(file1); task<file> f2 = open(file2); returnf1.then( [f2] (task<file> tr1 ) { f2.then( [tr1] (task<file> tr2) { return tr1.get().size() + tr2.get().size(); }) }); } size_tfile_sizes( string file1, string file2 ) { task<file> f1 = open(file1); task<file> f2 = open(file2); return f1.get().size() + f2.get().size(); }
Simple case .get .then size_tfile_sizes( string file1, string file2 ) { task<file> f1 = open(file1); task<file> f2 = open(file2); return f1.get().size() + f2.get().size(); } task<size_t> file_sizes( string file1, string file2 ) { task<file> f1 = open(file1); task<file> f2 = open(file2); return f1.then( [f2] (task<file> tr1 ) { f2.then( [tr1] (task<file> tr2) { return tr1.get().size() + tr2.get().size(); }) }); } .then + await task<size_t> file_sizes( string file1, string file2 ) resumable { task<file> f1 = open(file1); task<file> f2 = open(file2); return(await f1).size() + (awaitf2).size(); }
Branches and loops task<string> read( string file, string suffix ) { return open(file) .then([=](istream fi) { string ret, chunk; while( .get .then string read( string file, string suffix ) { istream fi = open(file).get(); string ret, chunk; while( (chunk = fi.read().get()).size() ) ret += chunk + suffix; return ret; } ?
Branches and loops task<string> read( string file, string suffix ) { return open(file) .then([=](istream fi) { auto ret = make_shared<string>(); auto next = make_shared<std::function<task<string>()>>( [=] { fi.read() .then([=](string chunk) { if( chunk.size() ) { *ret += chunk + suffix; return next(); } returntask_from_result(*ret); }); }); return(*next)(); }); } .get .then string read( string file, string suffix ) { istream fi = open(file).get(); string ret, chunk; while( (chunk = fi.read().get()).size() ) ret += chunk + suffix; return ret; }
Branches and loops task<string> read( string file, string suffix ) { return open(file) .then([=](istream fi) { auto ret = make_shared<string>(); auto next = make_shared<std::function<task<string>()>>( [=] { fi.read() .then([=](string chunk) { if( chunk.size() ) { *ret += chunk + suffix; return next(); } returntask_from_result(*ret); }); }); return(*next)(); }); } .get .then string read( string file, string suffix ) { istream fi = open(file).get(); string ret, chunk; while( (chunk = fi.read().get()).size() ) ret += chunk + suffix; return ret; } .then + await task<string> read( string file, string suffix ) resumable { istream fi = await open(file); string ret, chunk; while( (chunk = await fi.read()).size() ) ret += chunk + suffix; return ret; }
Await implementations • Iterator-Based Co-routines • Rewrite resumable function into a resumable state machine • Requires all locals to be hoisted to the heap • Resumable Side Stacks • Do not rewrite function logic • Each resumable function execution has its own “side” stack • Side stack lives beyond suspension/resuming until logical completion C# C++
Resumable Side Stack simulation Thread #1 Thread #2 void foo() { task<bool> t = async_bar(); somefunc(); boolb = t.get(); } task<bool> async_bar() resumable { do_work(); ... // sync calls awaitasync_work(); // More sync calls ... returntrue; } task<void> async_work() resumable { do_work(); awaitcreate_task( [] { longrunning (); }); return; } Main Stack Side Stack Side Stack <completed> <blocked> done! somefunc(); bool b = t.get() t = async_bar() <suspended> foo(); async_work is done! Longrunning is done! <completed> … … return task<bool> <suspended> … … … • … … return task<void> • await create_task(); • await async_work(); do_work(); do_work(); … More sync calls … async_bar(); async_work(); return true; return;