Can I use std::async without waiting for the future limitation?

后端 未结 4 775
伪装坚强ぢ
伪装坚强ぢ 2020-11-27 14:47

High level
I want to call some functions with no return value in a async mode without waiting for them to finish. If I use std::async the future object

4条回答
  •  时光说笑
    2020-11-27 15:42

    Rather than moving the future into a global object (and manually manage deletion of unused futures), you can actually move it into the local scope of the asynchronously called function.

    "Let the async function take its own future", so to speak.

    I have come up with this template wrapper which works for me (tested on Windows):

    #include 
    
    template
    void async_wrapper(Function&& f, Args&&... args, std::future& future,
                       std::future&& is_valid, std::promise&& is_moved) {
        is_valid.wait(); // Wait until the return value of std::async is written to "future"
        auto our_future = std::move(future); // Move "future" to a local variable
        is_moved.set_value(); // Only now we can leave void_async in the main thread
    
        // This is also used by std::async so that member function pointers work transparently
        auto functor = std::bind(f, std::forward(args)...);
        functor();
    }
    
    template // This is what you call instead of std::async
    void void_async(Function&& f, Args&&... args) {
        std::future future; // This is for std::async return value
        // This is for our synchronization of moving "future" between threads
        std::promise valid;
        std::promise is_moved;
        auto valid_future = valid.get_future();
        auto moved_future = is_moved.get_future();
    
        // Here we pass "future" as a reference, so that async_wrapper
        // can later work with std::async's return value
        future = std::async(
            async_wrapper,
            std::forward(f), std::forward(args)...,
            std::ref(future), std::move(valid_future), std::move(is_moved)
        );
        valid.set_value(); // Unblock async_wrapper waiting for "future" to become valid
        moved_future.wait(); // Wait for "future" to actually be moved
    }
    

    I am a little surprised it works because I thought that the moved future's destructor would block until we leave async_wrapper. It should wait for async_wrapper to return but it is waiting inside that very function. Logically, it should be a deadlock but it isn't.

    I also tried to add a line at the end of async_wrapper to manually empty the future object:

    our_future = std::future();
    

    This does not block either.

提交回复
热议问题