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

现在,我想for_each用 openmp 执行这个循环,就像我可以在for. 有什么诀窍可以使这成为可能吗?

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

4

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

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

应该共享的对象t和引用以及引用本身(基本上是实现引用的指针)应该是 firstprivate。f另一方面,OpenMP 标准禁止引用类型首先是私有的,并且不同的编译器供应商倾向于以不同的方式实现该标准。英特尔 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++ 编译器出现分段错误。

去搞清楚!

于 2013-08-02T17:21:36.457 回答