我能否使用OpenMP迭代遍历C++11的std::tuple?

3

我有以下代码,用于迭代std::tuple。 该代码来自这里

#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

3
我没看到for_each "循环",我看到的是递归,这两者不同。 - Nicol Bolas
@NicolBolas 我认为可以说递归在某种抽象意义上是一个循环。 - Johannes
1个回答

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(...);
}

重要的部分是在parallel区域内使用single结构体来调用for_each的顶层程序。这样只有一个线程会调用for_each,进而导致将f(std::get<I>(t));作为显式任务排队等待执行。其他线程在single结构末尾的隐式屏障处等待时,会开始从任务队列中取出任务并并行执行,直到队列为空为止。所有任务使用的变量的共享类别都明确给出,以确保清晰明了。 tf引用的对象应该是共享的,并且这些引用本身(实际上是实现引用的指针)应该是firstprivate的。另一方面,OpenMP标准禁止引用类型的变量被设为firstprivate,而各个编译器厂商的实现标准也不尽相同。Intel 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时它可以正常运行,但是在Intel C++编译器和PGI的C++编译器中却会打印出错误的初始值p,并导致分段错误。

真是难以理解!


谢谢!不过我无法编译这段代码 :(. 编译器报错说firstprivate有问题,但是我记得你说"我"不是问题吧?可能哪里出了错? - Johannes
1
就我对 C++ 模板的了解,像 I 这样的模板参数被视为字面常量而非变量,因此 I 不应该放置在 firstprivate(或任何数据共享子句)中。 - Hristo Iliev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接