我可以用openmp迭代C ++ 11 std :: tuple吗?

时间:2013-08-01 20:46:15

标签: c++ c++11 foreach openmp stdtuple

我有以下代码来迭代std::tuple。代码来自here

#include <tuple>
#include <utility>

template<std::size_t I = 0, typename FuncT, typename... Tp>
inline typename std::enable_if<I == sizeof...(Tp), void>::type
for_each(std::tuple<Tp...> &, FuncT) // Unused arguments are given no names.
{ }

template<std::size_t I = 0, typename FuncT, typename... Tp>
inline typename std::enable_if<I < sizeof...(Tp), void>::type
for_each(std::tuple<Tp...>& t, FuncT& f)
{
    f(std::get<I>(t));
    for_each<I + 1, FuncT, Tp...>(t, f);
}

现在,我想用openmp执行这个for_each循环,就像我在for上使用openmp一样。是否有可能使这成为可能?

注意:您可以修改上述代码或使用您自己for_each的任何其他版本。

1 个答案:

答案 0 :(得分:2)

C ++ 11模板语法对我来说非常陌生,但是像这样的递归问题最好使用显式OpenMP任务并行:

template<std::size_t I = 0, typename FuncT, typename... Tp>
inline typename std::enable_if<I < sizeof...(Tp), void>::type
for_each(std::tuple<Tp...>& t, FuncT& f)
{
    #pragma omp task firstprivate(I) shared(t,f)
    {
        f(std::get<I>(t));
    }
    for_each<I + 1, FuncT, Tp...>(t, f);
}

...

// Proper usage
#pragma omp parallel
{
    #pragma omp single
    for_each(...);
}

重要的一点是在for_each区域内的single构造中对parallel进行顶级调用。因此,只有一个线程会调用for_each,这反过来会导致f(std::get<I>(t));排队等待以后作为显式任务执行。其他线程在single结构末尾的隐式屏障处等待时,将开始从任务队列中拉出任务并并行执行它们,直到队列为空。为清楚起见,明确给出了任务使用的所有变量的共享类。

应该共享tf引用的对象,并且引用本身(基本上是实现引用的指针)应该是firstprivate。另一方面,OpenMP标准禁止引用类型为firstprivate,不同的编译器供应商倾向于以不同方式实现该标准。英特尔C ++编译器接受以下代码,它在任务中提供正确的结果,但引用的变量是私有化的(这是错误的):

void f(int& p)
{
   #pragma omp task
   {
      cout << "p = " << p << endl;
      p = 3;
      cout << "p' = " << p << endl;
   }
}

void f1()
{
   int i = 5;

   #pragma omp parallel
   {
      #pragma omp single
      f(i);
   }
   cout << "i = " << i << endl;
}

PGI的编译器给出了正确的结果,并没有私有化i。另一方面,GCC正确地确定p应该是firstprivate但是然后遇到标准中的禁止并且给出编译时错误。

如果将任务修改为:

#pragma omp task shared(p)
{
    ...
}

它可以正常使用GCC,但任务打印错误的初始值p,然后导致英特尔C ++编译器和PGI的C ++编译器出现分段错误。

去图!