运行 OpenMP 并行 for 循环时出现分段错误

时间:2021-03-17 22:22:16

标签: c++ parallel-processing openmp

对于下面的代码,我只想并行化其计算每个向量的第二个范数的最后一部分(每个向量的长度不同),但我收到了分段错误的错误。 另外,我不确定我是否在正确的地方使用了减少的总和。

还有一点是,我认为我只需要并行化外层循环,内层循环不需要这样做。对吗?

#include <iostream>
#include <vector>
#include <random>
#include <cmath>
#include <omp.h>
#include <fstream>
#include <cfloat>
#include <chrono>
using namespace std;

int main()
{
    int N = 1000000;       
    unsigned size;
    vector<vector<double>> c;
    default_random_engine g(0);
    uniform_real_distribution<double> d(0.0f, nextafter(1.0f, DBL_MAX));
    vector<double> b;
    
    for (int i = 0; i < N; i++) {
        size = pow(10, i % 4);
        vector<double> a;

        for (int j = 0; j < size; j++) {
            double number = d(g);
            a.push_back(number);
        }

        c.push_back(a);
    }       
    
    int i, j;
    double sum; 

    #pragma omp parallel for num_threads(4) shared(N) private(i,j,c,b) reduction (+: sum)
    for (int i = 0; i <N ; i++) {
       double sum = 0;
       for (int j = 0; j < c[i].size();j++) {
           sum = sum + pow(c[i][j],2);
       }

       double n = sqrt(sum);
       b.push_back(n);
    }
}

1 个答案:

答案 0 :(得分:3)

分段错误是由不复制向量的私有子句引起的。它将它们初始化为默认的空向量。如果您想从“主”线程执行复制,请改用 firstprivate。话虽如此,c 可以在这里分享。

此外,这里有几个要点:

  • sum 必须初始化为 0(循环外);
  • 并行循环范围内的 sum 变量影响其外部的 sum 变量(同样适用于 ij);
  • 无需声明本地 sum,OpenMP 为您完成;
  • 您可以移动 a 以避免不必要的副本并在使用前保留其大小(更快);
  • N 不需要在线程之间共享(最好进行本地复制);
  • 因为 b 是私有的,所以向它添加值是没有用的,除非在每个线程中本地读取它(这取决于你想要做什么)。如果你想在并行区域之外读取 b,你要么需要添加一个临界区,手动合并线程局部向量部分(更快),或者使用直接赋值(最简单的解决方案,可能是这里最快的) ).

这是更正后的代码:

#include <iostream>
#include <vector>
#include <random>
#include <cmath>
#include <omp.h>
#include <fstream>
#include <cfloat>
#include <chrono>
using namespace std;

int main()
{
    const int N = 1000000;
    vector<vector<double>> c;
    default_random_engine g(0);
    uniform_real_distribution<double> d(0.0f, nextafter(1.0f, DBL_MAX));
    c.reserve(N);

    for (int i = 0; i < N; i++) {
        const unsigned size = pow(10, i % 4);
        vector<double> a;
        a.reserve(size);

        for (int j = 0; j < size; j++) {
            const double number = d(g);
            a.push_back(number);
        }

        c.push_back(std::move(a));
    }

    double sum = 0.0;
    vector<double> b(N);

    #pragma omp parallel num_threads(4) firstprivate(N) shared(b,c,sum)
    {
        #pragma omp for reduction(+:sum)
        for (int i = 0; i < N ; i++) {
            double sumLocal = 0.0;

            for (int j = 0; j < c[i].size();j++) {
                sumLocal += pow(c[i][j], 2);
            }

            const double n = sqrt(sumLocal);
            b[i] = n;

            sum += sumLocal;
        }
    }
}