omp减少和lambda函数

Wal*_*ter 2 c++ lambda openmp c++11

以下简单代码没有给出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;
  }
Run Code Online (Sandbox Code Playgroud)

这返回零: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;
  }
Run Code Online (Sandbox Code Playgroud)

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

  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;
  }
Run Code Online (Sandbox Code Playgroud)

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

Ale*_*tov 7

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

  • @Walter,是的,它确实如此,否则我不会写那个评论.更具体地说,§2.9.3.6读取:_"reduction子句指定一个运算符和一个或多个列表项.对于每个列表项,在每个隐式任务中创建一个私有副本,并为运算符进行适当的初始化.在该区域中,原始列表项使用指定的运算符更新私有副本的值."_这是与实现相关的,这些私有副本位于,但它们肯定不同于并行区域范围之外的副本. (2认同)