Boost logo

Boost :

Subject: Re: [boost] Futures Review - Should packaged_task be CopyConstructible?
From: vicente.botet (vicente.botet_at_[hidden])
Date: 2009-01-26 17:00:31


Hi,

Currently when we set_wait_callback on a packaged_task, the packaged_task is given by reference to the callback function. This means that the packaged_task can not be moved.

As packaged_task is not CopyConstructible this limits quite a lot its use together with set_wait_callback. We need to pass it always by reference as functions parameters and can't be returned by a function.

I have tried to make a lazy_call function similar to spawn_task in the defined in N2709

template<typename F>
std::unique_future<typename std::result_of<F()>::type> spawn_task(F f)
{
    typedef typename std::result_of<F()>::type result_type;
    std::packaged_task<result_type()> task(std::move(f));
    std::unique_future<result_type> res(task.get_future());
    std::thread(std::move(task));
    return res;
}

Here it is

template<typename F>
std::unique_future<typename std::result_of<F()>::type> lazy_call(F f)
{
    typedef typename std::result_of<F()>::type result_type;
    std::packaged_task<result_type> task(std::move(f));
    task.set_wait_callback(invoke_lazy_task<result_type>())
    std::unique_future<result_type> res(task.get_future());
    return res;
}

but I need to return the packaged_task instead of the future because its lifetime must be longuer than the future->get() call. So I've tried to move the packaged_task which don't work either because the promise is broken

template<typename F>
std::packaged_task<typename std::result_of<F()>::type> lazy_call(F f)
{
    typedef typename std::result_of<F()>::type result_type;
    std::packaged_task<result_type> task(std::move(f));
    task.set_wait_callback(invoke_lazy_task<result_type>())
    return task;
}

Is there a way to implement this kind of function, other than wrapping the packaged_task on a CopyConstructible class?

template<typename F>
shared_ptr<std::packaged_task<typename std::result_of<F()>::type>> lazy_call(F f)
{
    typedef typename std::result_of<F()>::type result_type;
    shared_ptr<std::packaged_task<result_type>> task_ptr(new std::packaged_task<result_type()> (std::move(f)));
    task_ptr->set_wait_callback(invoke_lazy_task<result_type>())
    return task_ptr;
}

What is the rationale for making packaged_task movable only? Why should not be CopyConstructible?

Thanks,
Vicente

==========
    template <typename T>
    struct invoke_lazy_task {
        typedef void result_type;
        void operator()(packaged_task<T>& task) {
            try {
                task();
            } catch(task_already_started&) {}
        }
    };


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk