2

以下简单代码没有给出 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()给出不同结果的事实是编译器错误还是正确的?

4

1 回答 1

7

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

于 2012-08-22T10:49:14.690 回答