运行 OpenMP 并行 for 循环时出现分段错误
Segmentation fault when running an OpenMP parallel for loop
对于下面的代码,我只想并行化它的最后一部分,即计算每个向量的第二范数(每个向量的长度不同),但我收到了分段错误错误。
另外,我不确定我是否在正确的地方使用了总和的减少。
还有一点,我认为我只需要并行化外层循环,内层循环不需要这样做。对吗?
#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);
}
}
分段错误是由不复制向量的私有子句引起的。它将它们初始化为默认的空向量。如果您想从“主”线程执行复制,请改用 firstprivate。话虽这么说,c
可以在这里分享。
此外,还有几个要点:
sum
必须初始化为0(循环外);
- 并行循环范围内的
sum
变量会遮蔽其外部的sum
变量(同样适用于i
和j
);
- 无需声明本地
sum
,OpenMP 为您代劳;
- 您可以移动
a
以避免不必要的副本并在使用前保留其大小(更快);
N
不需要线程间共享(最好执行本地拷贝);
- 因为
b
是私有的,除非在每个线程中 local 读取它,否则向它添加值是没有用的(这取决于你想做什么)。如果你想在并行区域之外读取 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;
}
}
}
对于下面的代码,我只想并行化它的最后一部分,即计算每个向量的第二范数(每个向量的长度不同),但我收到了分段错误错误。 另外,我不确定我是否在正确的地方使用了总和的减少。
还有一点,我认为我只需要并行化外层循环,内层循环不需要这样做。对吗?
#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);
}
}
分段错误是由不复制向量的私有子句引起的。它将它们初始化为默认的空向量。如果您想从“主”线程执行复制,请改用 firstprivate。话虽这么说,c
可以在这里分享。
此外,还有几个要点:
sum
必须初始化为0(循环外);- 并行循环范围内的
sum
变量会遮蔽其外部的sum
变量(同样适用于i
和j
); - 无需声明本地
sum
,OpenMP 为您代劳; - 您可以移动
a
以避免不必要的副本并在使用前保留其大小(更快); N
不需要线程间共享(最好执行本地拷贝);- 因为
b
是私有的,除非在每个线程中 local 读取它,否则向它添加值是没有用的(这取决于你想做什么)。如果你想在并行区域之外读取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;
}
}
}