myl*_*les 3 c parallel-processing multicore openmp reduction
我有一些串行代码:
double* a = malloc((1000000) * sizeof(double));
double* b = malloc((1000000) * sizeof(double));
double totalA = 0;
for (int i = 0; i < 1000000; i++) {
if (i == 0) {
a[i] = sin(i);
}
b[i] = sin(i+1);
if (i < 1000000-1) {
a[i+1] = b[i];
}
totalA += a[i];
}
Run Code Online (Sandbox Code Playgroud)
totalA此串行循环后的输出是0.232883978073.
然后我有一个OpenMP版本(注意:所有变量都重新初始化):
double* a = malloc((1000000) * sizeof(double));
double* b = malloc((1000000) * sizeof(double));
double totalA = 0;
#pragma omp parallel for reduction(+:totalA)
for (int i = 0; i < 1000000; i++) {
if (i == 0) {
a[i] = sin(i);
}
b[i] = sin(i+1);
if (i < 1000000-1) {
a[i+1] = b[i];
}
totalA += a[i];
}
Run Code Online (Sandbox Code Playgroud)
但是,totalA此代码的输出是-0.733714826779.
我无法弄清楚为什么它与众不同.
谢谢.
UPDATE
经过一些游戏后,似乎if奇怪地忽略了循环中的语句.if块中的实际语句在循环的所有迭代上执行(就好像该if子句不存在).
例如,将if块更改为:
if (i < 555555) {
a[i+1] = b[i];
}
Run Code Online (Sandbox Code Playgroud)
似乎完全没有区别.
我仍然不知道这里发生了什么.
您的代码包含竞争条件.冲突的语句是a[i+1] = b[i];写入数组的赋值a和totalA += a[i];从中读取的语句a.
在您的代码中,无法保证在从该位置读取的迭代之前执行负责写入数组中特定位置的迭代.
为了进一步演示此问题,对包含冲突语句的循环段进行排序可以解决问题(但最有可能破坏性能):
#pragma omp parallel for ordered reduction(+:totalA)
for (int i = 0; i < 1000000; i++) {
if (i == 0) {
a[i] = sin(i);
}
b[i] = sin(i+1);
#pragma omp ordered
{
if (i < 1000000-1) {
a[i+1] = b[i];
}
totalA += a[i];
}
}
Run Code Online (Sandbox Code Playgroud)
最好完全避免这个问题并重写你的程序以摆脱循环携带的依赖:
#define N 1000000
double* a = malloc(N * sizeof(double));
double* b = malloc(N * sizeof(double));
double totalA = 0;
a[0] = sin(0);
totalA += a[0];
#pragma omp parallel for reduction(+:totalA)
for (int i = 0; i < N - 1; i++) {
b[i] = sin(i + 1);
a[i + 1] = b[i];
totalA += a[i + 1];
}
b[N - 1] = sin(N);
Run Code Online (Sandbox Code Playgroud)
最后,请注意,作为sin(0) ? 0.0,陈述
a[0] = sin(0);
totalA += a[0];
Run Code Online (Sandbox Code Playgroud)
可以简单地替换为
a[0] = 0.0;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1158 次 |
| 最近记录: |