如何使用返回任意类型的函数创建一个包含boost :: packaged_task <>的队列?

Abe*_*der 4 c++ queue templates boost packaged-task

我正在尝试构建一个需要由一个线程执行的函数的工作队列,并且可以由许多线程提供.为实现这一目标,我计划使用boost :: packaged_task和boost :: unique_future.这个想法是你会做的:

Foo value = queue.add(myFunc).get();

哪个会阻塞,直到执行该功能.所以queue.add(...)接受一个boost :: function,并返回一个boost :: unique_future.在内部,它然后使用boost :: function为其构造函数创建一个boost :: packaged_task.

我遇到的问题是boost :: function <...>每次都不一样.具体来说,它的返回值将会改变(但是,函数永远不会采用任何参数).因此,我必须有一个类似于以下内容的add函数:

template <typename ResultType>
boost::unique_future<ResultType> add(boost::function<ResultType ()> f) {
   boost::packaged_task<boost::function<ResultType ()> > task(f);
   queue.push_back(task);
   return task.get_future();
}
Run Code Online (Sandbox Code Playgroud)

好吧,这似乎并不太糟糕,但后来我遇到了如何定义'队列'的问题.我想我别无选择,只能使用boost :: any,因为类型不会是常量:

std::list<boost::any> queue; // note: I'm not concerned with thread-safety yet
Run Code Online (Sandbox Code Playgroud)

但是当我尝试实现我的executeSingle时,我遇到了一个问题(只从队列中取出一个项目来执行):

void executeSingle() {
    boost::any value = queue.back();
    boost::packaged_task<?> task = boost::packaged_task<?>(boost::move(value));
    // actually execute task
    task();
    queue.pop_back();
}
Run Code Online (Sandbox Code Playgroud)

'?' 表示我不确定的事情.我不能用模板调用executeSingle,因为它是从一个单独的线程调用的.我尝试使用boost :: any,但是我得到了错误:

  conversion from 'boost::any' to non-scalar type  boost::detail::thread_move_t<boost:thread>' requested.
Run Code Online (Sandbox Code Playgroud)

有趣的是,我实际上并不关心此时的packaged_task的返回类型,我只是想执行它,但我可以弄清楚模板的细节.

任何见解将不胜感激!

Luc*_*ton 5

你应该存储boost::function<void()>的.注意,boost::packaged_task<R>::operator()不返回任何东西; 它填充了相关的boost::future.事实上,即使它返回了你仍然可以使用的东西,boost::function<void()>因为你仍然对返回的值没有兴趣:你所关心的只是打电话queue.back()().如果是这种情况boost::function<void()>::operator(),请注意为您丢弃返回的值.

作为次要注释,您可能希望将add方法的签名更改为泛型类型Functor而不是a boost::function,并用于boost::result_of获取结果类型boost::packaged_task.

我的建议是一个整体:

template<typename Functor>
boost::future<typename boost::result_of<Functor()>::type>
queue::add(Functor functor) // assuming your class is named queue
{
    typedef typename boost::result_of<Functor()>::type result_type;
    boost::packaged_task<result_type> task(functor);
    boost::unique_future<result_type> future = task.get_future();
    internal_queue.push_back(boost::move(task)); // assuming internal_queue member
    return boost::move(future);
}

void
queue::executeSingle()
{
    // Note: do you really want LIFO here?
    queue.back()();
    queue.pop_back();
}
Run Code Online (Sandbox Code Playgroud)

编辑

如何处理内部的移动语义 queue::add

typedef typename boost::result_of<Functor()>::type result_type;
typedef boost::packaged_task<result_type> task_type;
boost::shared_ptr<task_type> task = boost::make_shared<task_type>(functor);
boost::unique_future<result_type> future = task->get_future();

/* boost::shared_ptr is possibly move-enabled so you can try moving it */
internal_queue.push_back( boost::bind(dereference_functor(), task) );

return boost::move(future);
Run Code Online (Sandbox Code Playgroud)

哪里dereference_functor可能是:

struct dereference_functor {
    template<typename Pointer>
    void
    operator()(Pointer const& p) const
    {
        (*p)();
    }
};
Run Code Online (Sandbox Code Playgroud)

您也可以将bind表达式替换为更清晰

boost::bind(&task_type::operator(), task)
Run Code Online (Sandbox Code Playgroud)

这也不需要自定义仿函数.但是,如果存在多次重载,task_type::operator()则可能需要消除歧义; 如果Boost.Thread中的未来更改引入了重载,代码也可能会中断.