C 如何在OpenMP中处理数据竞争?
我正在尝试使用OpenMP在数组中添加数字。以下是我的代码:C 如何在OpenMP中处理数据竞争?,c,for-loop,openmp,C,For Loop,Openmp,我正在尝试使用OpenMP在数组中添加数字。以下是我的代码: int* input = (int*) malloc (sizeof(int)*snum); int sum = 0; int i; for(i=0;i<snum;i++){ input[i] = i+1; } #pragma omp parallel for schedule(static) for(i=0;i<snum;i++) { int* tmpsum = i
int* input = (int*) malloc (sizeof(int)*snum);
int sum = 0;
int i;
for(i=0;i<snum;i++){
input[i] = i+1;
}
#pragma omp parallel for schedule(static)
for(i=0;i<snum;i++)
{
int* tmpsum = input+i;
sum += *tmpsum;
}
int*input=(int*)malloc(sizeof(int)*snum);
整数和=0;
int i;
对于(i=0;i使用reduce
子句()
int*input=(int*)malloc(sizeof(int)*snum);
整数和=0;
int i;
对于(i=0;i您的代码当前有一个,这就是结果不正确的原因。为了说明原因,让我们使用一个简单的示例:
您在两个线程上运行,数组是intinput[4]={1,2,3,4}
。您将sum
正确初始化为0
,并准备好开始循环。在循环的第一次迭代中,线程0和线程1从内存中读取sum
作为0
,然后将各自的元素添加到sum
,并将其写回内存。但是,这意味着线程0正在尝试将sum=1
写入内存(第一个元素是1
,和sum=0+1=1
),而线程1正试图将sum=2
写入内存(第二个元素是2
,和sum=0+2=2
)。此代码的最终结果取决于哪个线程最后完成,并因此最后写入内存,这是一种竞争条件。不仅如此,在这种情况下,代码可能生成的两个答案都不正确!有几种方法可以解决此问题;我将在下面详细介绍三种基本方法:
#pragma omp critical
:
在OpenMP中,有一个被称为临界
指令。该指令限制代码,以便一次只能有一个线程执行某项操作。例如,您的For
-循环可以写入:
#pragma omp parallel for schedule(static)
for(i = 0; i < snum; i++) {
int *tmpsum = input + i;
#pragma omp critical
sum += *tmpsum;
}
atomic
的性能通常明显优于critical
。但是,在您的特定情况下,它仍然不是最佳选择
减少
:
您应该使用的方法以及其他人已经建议的方法是reduce
。您可以通过将for
-循环更改为:
#pragma omp parallel for schedule(static) reduction(+:sum)
for(i = 0; i < snum; i++) {
int *tmpsum = input + i;
sum += *tmpsum;
}
#pragma omp并行计划(静态)缩减(+:sum)
对于(i=0;i
reduce
命令告诉OpenMP,当循环运行时,您希望每个线程跟踪自己的sum
变量,并将它们全部添加到循环末尾。这是最有效的方法,因为整个循环现在并行运行,当e> 每个线程的sum
值需要相加。sum
应该是一个缩减变量,缩减(+:sum)
在您的答案中,有很多地方您使用了进程,而正确的单词应该是线程。您可能希望更正此错误以避免混淆。@HristoIliev:对。我现在正在编写一个MPI代码,所以我整天都在考虑进程;因此出现了混淆。现在修复,谢谢。感谢您的回答,如果e var sum是一个数组,类似于“int sum[2]”。我使用了#pragma omp reduction(+:sum)和#pragma omp reduction(+:sum[0])#pragma omp reduction(+:sum[1]),不起作用!我能做什么?@YOung:不要将sum
作为数组;事实上,保持循环前的代码与之前完全相同。NikolayKondratyev在另一个答案中提供了一个工作代码示例。澄清一下:虽然我说过每个线程都会跟踪自己的sum
变量,但编译器会处理使用reduce
指令,您不需要自己设置数组。事实上,您已经看到,自己设置数组会混淆编译器,并导致代码产生错误的结果。@wolfPack88使用“reduce”,我得到了正确的答案。但我尝试使用“critical”或“automic”来完成此操作。我发现“reductioin”解决方案的速度几乎是其他解决方案的两倍;如何使用phtread或openmp来获得这种性能
#pragma omp parallel for schedule(static)
for(i = 0; i < snum; i++) {
int *tmpsum = input + i;
#pragma omp atomic
sum += *tmpsum;
}
#pragma omp parallel for schedule(static) reduction(+:sum)
for(i = 0; i < snum; i++) {
int *tmpsum = input + i;
sum += *tmpsum;
}