【问题标题】:How to parallel variadic function with TBB parallel_for?如何将可变参数函数与 TBB parallel_for 并行化?
【发布时间】:2015-04-23 21:42:11
【问题描述】:

我有一个像这样的模板可变参数函数,需要与 TBB parallel_for 函数并行化

template<typename T1, typename T2, typename... T3>
void func(T1 t1, T2 t2, std::size_t n, T3... t3)

我第一次尝试使用 lambda 函数,它能够捕获可变参数。它使用 C++11 特性用 clang 编译。

template<typename T1, typename T2, typename... T3>
void parallel_func(T1 t1, T2 t2, std::size_t n, T3 t3...){
     range r(n);
     apply_func = [=](range r){  //clang 6.1 can catch t3... here, gcc 4.8.3 could not
         std::size_t offset = r.begin();
         std::size_t n = r.end() -r.begin();
         func(t1, t2, n, (t3+offset)...);
     };
     tbb::parallel_for(r, apply_func);
}

但是,我使用的集群没有支持此功能的编译器。我不得不放弃 lambda 函数并编写一个类并将其传递给 parallel_for 函数。 我试过了:

template<typename T1, typename T2, typename... T3>
class ApplyFunc{
     ApplyFunc(T1 t1, T2 t2, T3... t3){
         t1_ = t1;
         t2_ = t2;
         t3_ = t3...;

     }
      void operator(range r){
         std::size_t offset = r.begin();
         std::size_t n = r.end() -r.begin();
         func(T1, T2, n, (T3+offset)...);
      }
      private:
         T1 t1_;
         T2 t2_;
         T3... t3_;
}

显然,不支持可变参数。我试过了 标准::元组 t3_; 但是,我无法将 std::tuple&lt;T3...&gt; 转换回可变参数。

【问题讨论】:

  • 你是在没有 c++11 支持的集群上编译代码?
  • @Jagannath 它是 gcc 4.8。不支持带有可变参数的 lambda。
  • 抱歉不能完全理解。 parallel_for 使用开始和结束索引进行迭代。那么你是如何通过课程的呢?您能否使用parallel_for_each 并将所有这些参数放入std::tuple 并在您的班级中有beginend。这行得通吗?
  • 你想并行化什么?并行调用ApplyFunc::operator()r 范围?
  • @yohjp TBB 将分割范围r,因此n 的值对于每个范围r 将是不同的。假设 T3 是指针类型。当parallel_for调用函数operator(range&amp; r)t3+n会有所不同

标签: c++ c++11 variadic-templates tbb variadic-functions


【解决方案1】:

您可以使用std::tuple&lt;Ts...&gt; 来保存可变参数值,并使用the indices trick 将其扩展为函数调用。 C++14 标准库为此提供了std::index_sequence

#include <tuple>

// forward compatibility for C++14 Standard Library
namespace cxx14 {
template<std::size_t...> struct index_sequence{};

template<std::size_t N, std::size_t... Is>
struct make_index_sequence : make_index_sequence<N-1, N-1, Is...>{};

template<std::size_t... Is>
struct make_index_sequence<0, Is...> : index_sequence<Is...>{};
}

template<typename T1, typename T2, typename... Ts>
class ApplyFunc{
public:
  ApplyFunc(T1 t1, T2 t2, Ts... ts)
    : t1_(t1), t2_(t2), pack_(ts...) {}

  template<std::size_t... Is>
  void call(range r, cxx14::index_sequence<Is...>){
    std::size_t offset = r.begin();
    std::size_t n = r.end() - r.begin();
    func(t1_, t2_, n, (std::get<Is>(pack_)+offset)...);
  }

  void operator()(range r){
    call(r, cxx14::make_index_sequence<sizeof...(Ts)>());
  }
private:
  T1 t1_;
  T2 t2_;
  std::tuple<Ts...> pack_;
};

【讨论】:

  • gcc 4.8.3 支持这个吗?
  • gcc 4.8.2 会,4.8.3 会。 LiveDemo
  • 太棒了!我会试一试。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-30
  • 1970-01-01
  • 2023-03-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多