1 / 13

C++ await Deon Brewis

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 {

lena
Télécharger la présentation

C++ await Deon Brewis

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. C++ awaitDeon Brewis std::future additions: isocpp.org/files/papers/N3721.pdf resumable functions: isocpp.org/files/papers/N3722.pdf

  2. 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; }

  3. Motivation .get(), .then() and await comparison

  4. 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(); }

  5. 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(); }

  6. 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(); }

  7. 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; } ?

  8. 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; }

  9. 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; }

  10. Technical drill-down

  11. 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++

  12. 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;

  13. Demo

More Related