使用 OpenMP 计算嵌套循环内部
Counter inside nested loops with OpenMP
我在 c program for making raster image to see image statistic : relative size of each basin ( pixel counting)
中使用计数器
我的程序很长,所以我制作了Minimal, Reproducible Example。
没有 OpenMP 的第一个程序显示了我想要实现的目标(所有像素的数量):
#include <stdio.h>
#include <stdlib.h>
int main()
{
int x;
int xMax = 100;
int y;
int yMax = 100;
int i= 0;
for (x = 0; x < xMax; x++) {
for (y = 0; y < yMax; y++)
{i++;}
}
printf("i = %d \t xMax*yMax = %d\n", i, xMax*yMax);
return 0;
}
它正确计算像素 (x,y):
i = xMax*yMax
当我添加 OpenMP 时就没那么容易了,但减少会有所帮助
#include <stdio.h>
#include <stdlib.h>
#include <omp.h> // OpenMP
int i= 0;
int main()
{
int x;
int xMax = 1000;
int y;
int yMax = 1000;
int all = xMax*yMax;
#pragma omp parallel for collapse(2) schedule(dynamic) reduction(+:i)
for (x = 0; x < xMax; x++) {
for (y = 0; y < yMax; y++)
{i++;}
}
printf("i = %d = %f*(xMax*yMax) \t where xMax*yMax = %d\n", i, (double)i/all, all);
return 0;
}
当我在另一个函数中隐藏计数器时,计数器未正确更新
#include <stdio.h>
#include <stdlib.h>
#include <omp.h> // OpenMP
int i= 0;
void P(){
i++;
}
int main()
{
int x;
int xMax = 1000;
int y;
int yMax = 1000;
int all = xMax*yMax;
#pragma omp parallel for collapse(2) schedule(dynamic) reduction(+:i)
for (x = 0; x < xMax; x++) {
for (y = 0; y < yMax; y++)
{P();}
}
printf("i = %d = %f*(xMax*yMax) \t where xMax*yMax = %d\n", i, (double)i/all, all);
return 0;
}
现在:
gcc p.c -Wall -fopenmp
./a.out
i = 437534 = 0.437534*(xMax*yMax) where xMax*yMax = 1000000
问题:函数内的计数器未正确更新
问题:我应该更改什么才能正确更新计数器?
问题是 reduction(+:i)
子句创建了一个局部变量 i
,您应该更改这个局部变量。但是,在您的代码中,您通过调用函数 P
来增加全局变量,这不是线程安全的(它在增加时有竞争条件)。因此,您只需确保在调用函数 P
:
时增加本地 i
void P(int& i){
i++;
}
//in main:
for (y = 0; y < yMax; y++)
{P(i);}
另一个(但速度较慢)选项是通过使用原子操作使函数 P
线程安全。在这种情况下,您根本不需要减少:
void P(){
#pragma omp atomic
i++;
}
我在 c program for making raster image to see image statistic : relative size of each basin ( pixel counting)
中使用计数器我的程序很长,所以我制作了Minimal, Reproducible Example。
没有 OpenMP 的第一个程序显示了我想要实现的目标(所有像素的数量):
#include <stdio.h>
#include <stdlib.h>
int main()
{
int x;
int xMax = 100;
int y;
int yMax = 100;
int i= 0;
for (x = 0; x < xMax; x++) {
for (y = 0; y < yMax; y++)
{i++;}
}
printf("i = %d \t xMax*yMax = %d\n", i, xMax*yMax);
return 0;
}
它正确计算像素 (x,y):
i = xMax*yMax
当我添加 OpenMP 时就没那么容易了,但减少会有所帮助
#include <stdio.h>
#include <stdlib.h>
#include <omp.h> // OpenMP
int i= 0;
int main()
{
int x;
int xMax = 1000;
int y;
int yMax = 1000;
int all = xMax*yMax;
#pragma omp parallel for collapse(2) schedule(dynamic) reduction(+:i)
for (x = 0; x < xMax; x++) {
for (y = 0; y < yMax; y++)
{i++;}
}
printf("i = %d = %f*(xMax*yMax) \t where xMax*yMax = %d\n", i, (double)i/all, all);
return 0;
}
当我在另一个函数中隐藏计数器时,计数器未正确更新
#include <stdio.h>
#include <stdlib.h>
#include <omp.h> // OpenMP
int i= 0;
void P(){
i++;
}
int main()
{
int x;
int xMax = 1000;
int y;
int yMax = 1000;
int all = xMax*yMax;
#pragma omp parallel for collapse(2) schedule(dynamic) reduction(+:i)
for (x = 0; x < xMax; x++) {
for (y = 0; y < yMax; y++)
{P();}
}
printf("i = %d = %f*(xMax*yMax) \t where xMax*yMax = %d\n", i, (double)i/all, all);
return 0;
}
现在:
gcc p.c -Wall -fopenmp
./a.out
i = 437534 = 0.437534*(xMax*yMax) where xMax*yMax = 1000000
问题:函数内的计数器未正确更新
问题:我应该更改什么才能正确更新计数器?
问题是 reduction(+:i)
子句创建了一个局部变量 i
,您应该更改这个局部变量。但是,在您的代码中,您通过调用函数 P
来增加全局变量,这不是线程安全的(它在增加时有竞争条件)。因此,您只需确保在调用函数 P
:
i
void P(int& i){
i++;
}
//in main:
for (y = 0; y < yMax; y++)
{P(i);}
另一个(但速度较慢)选项是通过使用原子操作使函数 P
线程安全。在这种情况下,您根本不需要减少:
void P(){
#pragma omp atomic
i++;
}