2011-01-25 2 views
1

다음 C 코드에서 중첩 루프에서 OpenMP를 사용하고 있습니다. 경쟁 조건이 발생하기 때문에, 나는 마지막에 원자 작업을 수행 할 :컴파일러가 OpenMP pragma를 무시하는 이유는 무엇입니까?

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의 프라그 마를 검사 할 때 또는 내가 오류가 발생하지 않는 이유는

는 PS 마지막 변경을 할 때 더 엄격 컴파일러를 말할 수 있는지, 여기에 무슨 일이 잘못 궁금해 :

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

PS2 : 새로운 코드 나에게 같은 문제를 제공하고 길레스피의 아이디어를 기반으로 :

#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); 
} 

답변

3
  1. 플래그 -Wall을 사용하면 pragma 오류가 강조 표시됩니다. 예를 들어, atomic의 철자를 잘못 입력하면 다음과 같은 경고 메시지가 표시됩니다.

    main.c:15: warning: ignoring #pragma omp atomic1

  2. 난 당신이 알고 있어야 해요,하지만 단지의 경우, 귀하의 예제는 당신이 OMP 평행을 사용하면 모든 변수가 공유 할 수 있도록, 기본이되는 reduction

  3. 으로 취급한다 . 이것은 당신이 원하는 것이 아닙니다. 예를 들어, 각 스레드는 다른 값 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]; 
        } 
    } 
    
+0

안녕하세요, 2) 예, 전 환원 전에 사용했지만 동일한 문제! 3) 그래서, 축소도 원 자성도 여기 도움이되지 않는 것 같습니다. 무슨 일이 벌어지고 있습니까? – flow

+0

@Werner : 원자를 사용할 때 나는 항상 정확한 답을 얻습니다. 내 대답 – csgillespie

+0

프로그램에 효과적으로 코드를 추가 할 것입니다. 내 이전 오류는 "a"와 "b"가 병렬 내부에 정의되어야한다는 것과 g ++ 컴파일러를 사용해야한다는 것을 깨달았습니다. gcc 만 사용하기 전에. 이제는 코드를 수정하고 새로운 것들을 추가했습니다. PS2에 대한 질문을 편집 할 때 볼 수 있듯이, 이제는 g ++와 다른 결과를 얻었습니다. 너무 많은 작업을 수행했기 때문입니까? – flow

0

첫째, 구현에 따라 감소가 원자 사용하는 것보다 더 좋을 수 있습니다. 나는 둘 다 시도하고 그들을 볼 시간.

둘째, 원자에서 나가면 인종과 관련된 문제 (잘못된 결과)가 보일 수도 있고 보이지 않을 수도 있습니다. 그것은 하나의 실행에서 다음 실행으로 완전히 다를 수있는 타이밍에 관한 것입니다. 나는 결과가 150,000 회의 달리기에서 한 번만 잘못되었거나 항상 틀린 경우를 보았습니다.

세 번째로, pragma 뒤에있는 아이디어는 사용자가 효과가 없다면 사용자가 알 필요가 없다는 것입니다. 그 외에, 유닉스 (그리고 파생 상품)의 철학은 문제가 발생하지 않는다면 조용하다는 것이다. 말하자면, 많은 구현체에는 일종의 플래그가 있기 때문에 사용자는 무슨 일이 일어나고 있는지 모르기 때문에 더 많은 정보를 얻을 수 있습니다. GCC로 시도해 볼 수 있습니다. 적어도 oh_my_god 플래그는 무시되어야합니다.

+0

예, -Wall (죄송합니다, 완전히 잊어 버렸습니다.) 이제 플러그인 플러그 접속 식 oh_my_god가 오류를 표시합니다. 원자력 프라그마는 아무런 오류가 없지만, 원자력 프라그마가 실제로 작동한다는 보장이 무엇인지 궁금합니다. 그것은 나를 위해 무익 해 보입니다. – flow

0

당신은 그래서 유일한 병렬 for 루프에있을 것입니다

#pragma omp parallel for shared(S2) 
    for(int a=0; a<128; a++){ 
    .... 

있습니다.

당신이

#pragma omp parallel 
{ 
#pragma omp 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; 
    } // end of second for 
    } // end of 1st for 
} // end of parallel code 
return S2; 
} // end of function 

을 할 필요가 원자 또는 축소를 원한다면 그렇지 않으면 모든 # 후에 언급 될 것이다

0

나는 이것이 이전 게시물입니다 알지만,이 문제가 생각 gcc, -fopenmp의 매개 변수 순서는 컴파일 라인의 끝에 있어야합니다.

관련 문제