Bringing await to C++

Sign in to queue

Description

Modern application development requires asynchronous programming techniques. For C++, this generally involves using libraries employing promises or futures or tasks, a la PPL and std::future. What about adding 'await' to the C++ language itself? It's clear that 'await' has done wonders for C#. What would it look like for C++? How does it work? This detailed walkthrough will show the benefits of using ‘await’ vs. PPL or std::future, dig into it's implementation in VC++, and explain the differences between C++ await and C# await. 

Day:

3

Embed

Download

Download this episode

The Discussion

  • User profile image
    felix9

    wow wow wow

  • User profile image
    khourig

    Regarding the continuation context of an await, it would be simple to supply the context if await looked more like a function. That is, "await( async_function(), context )" where context is an optional parameter.

  • User profile image
    Marat Abrarov

    They know about Asio! The know (and don't make it a secret) about heaviness of side stack creation for runtime memory (heap?) in a scenario of mass (TCP socket server) usage of "await". They even working over solution for such scenario. VC++ team is really great. Thanks a lot.

  • User profile image
    tomkirbygre​en

    'wow wow wow' is entirely appropriate, at the moment you need to take a dependency on C# and interop to native which is obviously horrible ( all that extra machinery and runtime overhead ). Just hope there's going to be a Visual Studio 2014 so we can get await for C++ into production with a go-live licence as soon as possible. It's too yummy to keep in the labs.

    Then we need the ISO folks to include it in C++ 17.

  • User profile image
    akhare

    Very interesting -- can we expect it in a CTP?  Are parameters to async functions captured and propagated to the side stack? Does this imply a change to the ABI?

  • User profile image
    DeonBrewis

    Thanks for the comments everyone!

    Akhare, yes, we are trying to target the next CTP.

    Parameters to the async function are indeed captured and propagated to the side stack, but it happens inside a trampoline function. The trampoline function thus ensures that there isn't a change in ABI required. i.e. A caller can treat:  "task<T> func() resumable" the same as "task<T> func()".

    In fact, we don't currently have a specific need to put "resumable" on declarations - only on definitions. Hence, it's theoretically completely transparent to callers. We however will require it on declarations for now, just in case. It's easier to remove such a requirement later - not so easy to add it. We've imagined some optimizations if the caller knows it is calling into a resumable function (which will require it on declaration, and thus imply an ABI change), but nothing really concrete.

  • User profile image
    Moondevil

    @tomkirbygreen

    4 years plus the time that at least intel, gcc, clang and vc++ support it, are too long in computer time.

    Who knows how the computing landscape will look like in 2020, time the C++17 should be available in mainstream compilers, maybe.

  • User profile image
    shaoyuan1943

    Interesting!thank you!

  • User profile image
    Mikhail

    You can write a library that does 'await'.

    Please check this - http://habrahabr.ru/post/185706/

    All you need is this code:

    using __Coro=boost::coroutines::coroutine<void()>;
    void Post2UI(const void* coro);
    template<typename L> auto __await_async(const __Coro* coro, __Coro::caller_type& yield, L lambda)->decltype(lambda())
    {
    auto f=async(launch::async, [=](){
    auto r=lambda();
    Post2UI(coro);
    return r;
    });
    yield();
    return f.get();
    }
    void CallFromUI(void* c)
    {
    __Coro* coro=static_cast<__Coro*>(c);
    (*coro)();
    if(!*coro) delete coro;
    }
    #define async_code(block) { __Coro* __coro=new __Coro; *__coro=__Coro([=](__Coro::caller_type& __yield){block});}
    #define await_async(l) __await_async(__coro, __yield, l)

    Plus GUI-specific implementation of two functions - Post2UI and OnAsync, that need to be written once for the whole application on given GUI framework. (It doesn't need to be GUI, it might be somethig like boost::asio::io_service).

  • User profile image
    Evgeny​LPanasyuk

    Full emulation of await feature from C# language in C++ based on Stackful Coroutines from Boost.Coroutine library: https://github.com/panaseleus/await_emu

    int bar(int i)
    {
    auto result = await boost::async([i]{ return reschedule(), i*100; });
    // await "transforms" rest of code into continuation and attaches it to boost::future::then
    // (any other mechanism similar to .then can be used)
    return result + i*10;
    }

    This proof-of-concept shows that exact syntax of await feature can be emulated with help of Stackful Coroutines, demonstrating that it is superior mechanism.

  • User profile image
    fjestis

    How await concept relates to Haskell "bind" and "then" operators used in monads, namely `>>=` and `>>`? Both concepts lead to pretty similar thing I think, especially that iterator-based co-routines.

  • User profile image
    episteme

    GREAT!
    I've tried to use __await/__resumable on C++/CX StoreApp, works fine!

    - f.fukuda, Japan, MVP for Visual C++

  • User profile image
    stepik777

    Resumable functions are like do-notation in Haskell (and await is like <-). But for one specific monad - std::future.

  • User profile image
    Raman_Sharma

Add Your 2 Cents