omp减少和lambda函数

时间:2012-08-22 10:41:38

标签: c++ lambda c++11 openmp

以下简单代码未提供gcc 4.7.0的预期结果。这是正确还是错误?

  unsigned count_err(std::vector<unsigned> const&num, unsigned mask)
  {
    unsigned c=0;
    // enables to reuse the lambda later (not in this simple example)
    auto f = [&] (unsigned i) { if(i&mask) ++c; };
#pragma omp parallel for reduction(+:c)
    for(unsigned i=0; i<num.size(); ++i)
      f(num[i]);
    return c;
  }

这返回零:没有完成c从lambda函数的减少。顺便说一句,我期望结果是串行函数返回的结果

  unsigned count_ser(std::vector<unsigned> const&num, unsigned mask)
  {
    unsigned c=0;
    auto f = [&] (unsigned i) { if(i&mask) ++c; };
    std::for_each(num.begin(),num.end(),f);
    return c;
  }

以下实现给出了预期的结果(在这两种情况下,将减少变量的增量的代码定义移动到并行区域中)

  unsigned count_ok1(std::vector<unsigned> const&num, unsigned mask)
  {
    unsigned c=0;
    auto f = [&] (unsigned i) -> bool { return i&mask; };
#pragma omp parallel for reduction(+:c)
    for(unsigned i=0; i<num.size(); ++i)
      if(f(num[i])) ++c;
    return c;
  }

  unsigned count_ok2(std::vector<unsigned> const&num, unsigned mask)
  {
    unsigned c=0;
#pragma omp parallel reduction(+:c)
    {
      auto f = [&] (unsigned i) { if(i&mask) ++c; };
#pragma omp for
      for(unsigned i=0; i<num.size(); ++i)
        f(num[i]);
    }
    return c;
  }

事实是count_err()给出了不同的结果编译器错误或正确吗?

1 个答案:

答案 0 :(得分:7)

我认为这不是编译器错误。这是我的解释。我想在你的第一个例子中,lambdas持有对全局c变量的引用。我们进入for循环时创建了c的线程本地副本。因此线程正在递增相同的全局变量(没有任何同步)。当我们退出循环时,c的线程局部副本(全部等于零,因为lambdas不知道它们)总结为0。count_ok2版本有效,因为lambdas正在保留对本地c份副本的引用。