QingYun
QingYun

Reputation: 869

Implement a function similar to async

I have a function foo that returns a future. foo will register a callback which will be called after foo returns.

future<int> foo() {
    promise<int> p;
    future<int> ret(p.get_future());
    thread(bind([] (promise<int> &&p) {
        this_thread::sleep_for(chrono::seconds(3));
        p.set_value(10);
    }, move(p))).detach();
    return move(ret);
}

int main()
{
    auto f = foo();
    cout << f.get() << endl;
    return 0;
}

But it seems like that std::bind forwards the rvalue reference as a lvalue reference so that can not be successfully compiled. Is there any way to fix it?


I have to write an ugly class to move the promise object:

template<typename T>
class promise_forward {
    promise<T> promise_;

public:
    promise_forward(promise<T> &&p) : 
        promise_(move(p)) {}

    promise_forward(promise_forward<T> &&other) : 
        promise_(move(other.promise_)) {}

    operator promise<T> () {
        return move(promise_);
    }
};

future<int> foo() {
    promise<int> p;
    future<int> ret(p.get_future());
    thread(bind([] (promise<int> &&p) {
        this_thread::sleep_for(chrono::seconds(3));
        p.set_value(10);
    }, promise_forward<int>(move(p)))).detach();
    return ret;
}

int main()
{
    auto f = foo();
    cout << f.get() << endl;
    return 0;
}

Upvotes: 2

Views: 131

Answers (1)

Drop
Drop

Reputation: 13005

You, basically, doesn't need std::bind here (well , I believe so =)). Here is a quick draft of a simplest async task launcher. It almost same as yours, but, just a little more generic: it can accept any function objects and it is less intrusive: function objects doesn't know nothing about promises or threading at all.

There are may be mistakes (I'm quite sure they are). And, of course, it is far far away, from std::async implementation (which, generally, more than just thread launcher, but, ideally, have a huge thread management back-end).

#include <thread>
#include <future>
#include <iostream>
#include <chrono>


template< class Function, class... Args>
std::future<typename std::result_of<Function(Args...)>::type> my_async(Function && f, Args && ... args)
{
    typedef typename std::result_of<Function(Args...)>::type ret_type;

    std::promise<ret_type> p;

    auto fut = p.get_future();


    // lambda in separate variable, just to improve readability 
    auto l = [](Function && f, Args && ... args, std::promise<ret_type> && p)
    {
        p.set_value(f(args...));
    };

    std::thread th(l, std::move(f), std::move(args...), std::move(p));

    th.detach();

    return std::move(fut);

}

int wannaRunAsync(int i)
{
    return i;
};

int main()
{

    auto fut = my_async(&wannaRunAsync, 42);

    auto fut2 = my_async([](int i) -> int { return i; }, 42);

    std::cout << fut.get() << std::endl;
    std::cout << fut2.get() << std::endl;

    std::cin.get();

    return 0;
}

I was able to compile and run it with g++-4.8 and clang++ but with msvc 2012 and 2013 preview it doesn't even compiles (probably, due to errors).

I've not tested this code at all, so be careful =) Hope it helps.

Upvotes: 1

Related Questions