c - 为什么编译器会忽略 OpenMP 编译指示?

标签 c openmp race-condition pragma

在下面的 C 代码中,我在嵌套循环中使用 OpenMP。由于出现竞争条件,我想在最后执行原子操作:

double mysumallatomic() {

  double S2 = 0.;
  #pragma omp parallel for shared(S2)
  for(int a=0; a<128; a++){
    for(int b=0; b<128;b++){
      double myterm = (double)a*b;
      #pragma omp atomic
      S2 += myterm;
    }
  }
  return S2;
}

问题是 #pragma omp atomic 对程序行为没有影响,即使我删除它,也没有任何反应。即使我将其更改为 #pragma oh_my_god,我也不会出错!

我想知道这里出了什么问题,我是否可以告诉编译器在检查 omp pragma 时更加严格,或者为什么我在进行最后一次更改时没有收到错误

PS:编译我使用:

gcc-4.2 -fopenmp main.c functions.c -o main_elec_gcc.exe

PS2:给我同样问题的新代码,基于 gillespie 的想法:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <omp.h>
#include <math.h>

#define NRACK 64
#define NSTARS 1024

double mysumallatomic_serial(float rocks[NRACK][3], float moon[NSTARS][3],
                             float qr[NRACK],float ql[NSTARS]) {
  int j,i;
  float temp_div=0.,temp_sqrt=0.;
  float difx,dify,difz;
  float mod2x, mod2y, mod2z;
  double S2 = 0.;

  for(j=0; j<NRACK; j++){
    for(i=0; i<NSTARS;i++){     
      difx=rocks[j][0]-moon[i][0];
      dify=rocks[j][1]-moon[i][1];
      difz=rocks[j][2]-moon[i][2];
      mod2x=difx*difx;
      mod2y=dify*dify;
      mod2z=difz*difz;
      temp_sqrt=sqrt(mod2x+mod2y+mod2z);
      temp_div=1/temp_sqrt;
      S2 += ql[i]*temp_div*qr[j];       
    }
  }
  return S2;
}

double mysumallatomic(float rocks[NRACK][3], float moon[NSTARS][3], 
                      float qr[NRACK],float ql[NSTARS]) {
  float temp_div=0.,temp_sqrt=0.;
  float difx,dify,difz;
  float mod2x, mod2y, mod2z;
  double S2 = 0.;

  #pragma omp parallel for shared(S2)
  for(int j=0; j<NRACK; j++){
    for(int i=0; i<NSTARS;i++){
      difx=rocks[j][0]-moon[i][0];
      dify=rocks[j][1]-moon[i][1];
      difz=rocks[j][2]-moon[i][2];
      mod2x=difx*difx;
      mod2y=dify*dify;
      mod2z=difz*difz;
      temp_sqrt=sqrt(mod2x+mod2y+mod2z);
      temp_div=1/temp_sqrt;
      float myterm=ql[i]*temp_div*qr[j];    
      #pragma omp atomic
      S2 += myterm;
    }
  }
  return S2;
}
int main(int argc, char *argv[]) {
  float rocks[NRACK][3], moon[NSTARS][3];
  float qr[NRACK], ql[NSTARS];
  int i,j;

  for(j=0;j<NRACK;j++){
    rocks[j][0]=j;
    rocks[j][1]=j+1;
    rocks[j][2]=j+2;
    qr[j] = j*1e-4+1e-3;
    //qr[j] = 1;
  }

  for(i=0;i<NSTARS;i++){
    moon[i][0]=12000+i;
    moon[i][1]=12000+i+1;
    moon[i][2]=12000+i+2;
    ql[i] = i*1e-3 +1e-2 ;
    //ql[i] = 1 ;
  }
  printf(" serial: %f\n", mysumallatomic_serial(rocks,moon,qr,ql));
  printf(" openmp: %f\n", mysumallatomic(rocks,moon,qr,ql));
  return(0);
}

最佳答案

  1. 使用标志 -Wall 突出显示编译指示错误。例如,当我拼错 atomic 时,我会收到以下警告。

    main.c:15: 警告:忽略#pragma omp atomic1

  2. 我相信您知道,但以防万一,您的示例应该使用reduction

  3. 当您使用 omp parallel 时,默认情况下所有变量都是共享的。这不是你想要的。例如,每个线程将有不同的值 difx。相反,您的循环应该是:

    #pragma omp parallel for default(none),\
    private(difx, dify, difz, mod2x, mod2y, mod2z, temp_sqrt, temp_div, i, j),\
    shared(rocks, moon, ql, qr), reduction(+:S2)
    for(j=0; j<NRACK; j++){
      for(i=0; i<NSTARS;i++){
        difx=rocks[j][0]-moon[i][0];
        dify=rocks[j][1]-moon[i][1];
        difz=rocks[j][2]-moon[i][2];
        mod2x=difx*difx;
        mod2y=dify*dify;
        mod2z=difz*difz;
        temp_sqrt=sqrt(mod2x+mod2y+mod2z);
        temp_div=1/temp_sqrt;
        S2 += ql[i]*temp_div*qr[j];  
      }
    }
    

关于c - 为什么编译器会忽略 OpenMP 编译指示?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4793363/

相关文章:

linux设备驱动文件操作: it is possible to have race conditions?

c - LPSTREAM 将整个 Stream 内容读入 unsigned char* 数组

c - PDCurses mvprintw 结构错误

c++ - OpenMP 使用映射并行化 for 循环

c# - 锁字典不断增长,不知如何清理?

c++ - Thread Sanitizer 是否可用?

c - 在 Linux 内核中, spin_lock_irqsave() 是否可以保护我免受信号处理程序、页面错误、schedule() 调用的影响?

C指针和内存泄漏

c++ - OpenMP 还原同步错误

c - 为 OpenMP 中的每个内部循环启动一个线程