代码之家  ›  专栏  ›  技术社区  ›  Andrew

为什么我的并行std::for_each只使用1个线程?

  •  0
  • Andrew  · 技术社区  · 3 年前

    我试图将这段C++代码并行化(计算点的连续傅里叶变换,建模为狄拉克脉冲),这段代码可以正确编译和工作,但它只使用1个线程。我还需要做些什么来让多个线程工作吗?这是在具有4个内核(8个线程)的Mac上使用GCC 10编译的。

    vector<double> GetFourierImage(const Point pts[],
                                   const int num_samples,
                                   const int res,
                                   const double freq_step) {
      vector<double> fourier_img(res*res, 0.0);
      double half_res = 0.5 * res;
    
      vector<int> rows(res);
      std::iota(rows.begin(), rows.end(), 0);
      std::for_each(  // Why doesn't this parallelize?
          std::execution::par_unseq,
          rows.begin(), rows.end(),
          [&](int i) {
        double y = freq_step * (i - half_res);
        for (int j = 0; j < res; j++) {
          double x = freq_step * (j - half_res);
    
          double fx = 0.0, fy = 0.0;
          for (int pt_idx = 0; pt_idx < num_samples; pt_idx++) {
            double dot = (x * pts[pt_idx].x) + (y * pts[pt_idx].y);
            double exp = -2.0 * M_PI * dot;
            fx += cos(exp);
            fy += sin(exp);
          }
          fourier_img[i*res + j] = sqrt((fx*fx + fy*fy) / num_samples);
        }
      });
    
      return fourier_img;
    }
    
    0 回复  |  直到 3 年前
        1
  •  3
  •   Ryan H    3 年前

    在GCC 9中,当使用不同的执行策略时,对TBB有很强的依赖性,如果不存在这种依赖性,那么构建就会失败。在GCC 10中(以及GCC 11中),情况发生了变化,如果库不存在,则for_each将默认为顺序循环。这可以在以下网址看到 https://github.com/gcc-mirror/gcc/blob/releases/gcc-10.1.0/libstdc++-v3/include/bits/c++config#L679 。要解决您的问题,请尝试使用链接到TBB -ltbb 。这解决了您在使用GCC 11.2的Ubuntu 20.04上遇到的问题。

        2
  •  0
  •   mismou    2 年前

    我在macOS上也遇到了同样的问题。在我的例子中,将tbb头文件的路径添加到包含搜索路径中解决了这个问题。对于安装了自制程序的g++-11和tbb,这是 g++-11 -O3 -std=c++17 -I/opt/homebrew/include -o main main.cpp -ltbb ; 此目录包含tbb头文件夹。如果我不添加这个标志,我的代码就会编译,但只运行单线程,如@Andrew所述。就我而言,添加 -fopenmp 旗帜不是必需的,但 -ltbb 正如@Ryan H.所指出的那样。