模板函数上的C ++ Template类成员

时间:2017-09-05 01:50:04

标签: c++ multithreading templates metaprogramming

我有一个线程池,应该接受任何std :: packaged_task并给出未来。

template<typename RetType>
template<typename Args...>
std::future<RetType> submitWork(std::packaged_task<RetType(Args...)>&& callableWork>);

正如您所看到的,packaged_task是模板化的。现在我的线程池使用无锁队列作为类

的成员
class ThreadPool
{
public:
private:
    llQueue<boost::variant<???>> workQueue;
}

我希望工作队列是submitWork被调用的类型的变体。例如:此代码

bool runByPool(int var)
{
     //do stuff
}

int runAlso(char c)
{
    //do other stuff
}

ThreadPool pool; // 4 worker threads
pool.submitWork<bool(int)>(std::bind(runByPool, 1));
pool.submitWork<int<c>>(std::bind(runAlso, 'a'));

在编译时为workQueue提供以下类型:

llQueue<boost::variant<std::packaged_task<bool(int)>,
                       std::packaged_task<int(c)>
                      >
        >

如何让班级成员使用模板化提交作业的类型?我想强制llQueue只保存std :: packaged_task,我使用了一个变体,这样我可以避免堆分配,因为这需要高度,高性能。

我想避免堆分配,我需要相同的池才能执行任何返回类型或参数类型的工作

1 个答案:

答案 0 :(得分:1)

您发布的大多数代码都无法编译。

pool.submitWork<bool(int)>(std::bind(runByPool, 1));

std::bind(runByPool, 1)的签名是bool()而不是bool(int)。同样的错误在你的另一个例子中,好吧,忽略那里的其他语法错误。

std::future<RetType> submitWork(std::packaged_task<RetType&&(Args&&...)&& callableWork>);
这个签名是精神错乱的。它应该是;

std::future<RetType> submitWork(std::packaged_task<RetType(Args...)> callableWork);

接下来,采取仍然需要非均匀类型的工作几乎没有意义。这反映在您的示例中。

事实上,在这里执行打包任务毫无意义。

std::future<RetType> submitWork(std::function<RetType()> callableWork>);

更有意义。你接受一个返回T的操作,并返回一个未来的T。

llQueue<boost::variant<???>> workQueue;

这里不需要变体。您需要一个可以运行的任务队列。它们的返回类型应该已经被路由到其他地方,并且它们的参数已经绑定了。

llQueue<std::function<void()>> workQueue;

现在仍存在技术问题。 std::function<void()>要求它是可复制的;将可调用工作连接到未来的简单方法就是为您提供不可复制的打包任务。

有几种方法可以解决这个问题。第一种方法是将打包的任务推送到共享的ptr中,然后将其存储在函数中。第二个是注意packaged_task<T()>是仅可以使用签名void()调用的移动,可以存储在packaged_task<void()>中。

所以我们走了一圈。

struct ThreadPool {
  template<class F, class R=std::result_of_t<F&()>>
  std::future<R> submitWork(F f){
    auto task=std::packaged_task<R()>(std::move(f));
    auto r=task.get_future();
    workQueue.push_back(std::packaged_task<void()>(std::move(task)));
    return r;
  }
  std::vector<std::packaged_task<void()>> workQueue;
  // or:
  //llQueue<std::packaged_task<void()>> workQueue;
  // with changes to how things are enqueued
};

作为奖励,它会为您推断出返回类型。 Live example

我相信我已经看到至少有一个C ++编译器搞砸了并使打包的任务需要可复制的内容。因此共享的ptr包含功能可能是您的备份计划。