Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/spring-mvc/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 如何在OpenMP中处理数据竞争?_C_For Loop_Openmp - Fatal编程技术网

C 如何在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

我正在尝试使用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 = 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;
}