2017-11-17 7 views
1

많은 반복을 실행하는 코드가 있으며 조건이 충족되는 경우에만 반복 결과가 저장됩니다. 이것은 자연스럽게 while 루프로 표현됩니다. 각 실현은 독립적이기 때문에 코드를 병렬로 실행하려고합니다. 그래서이있다 :OpenMP while 루프

while(nit<avit){ 
    #pragma omp parallel shared(nit,avit) 
    { 
     //do some stuff 
     if(condition){ 
      #pragma omp critical 
      { 
       nit++; 
       \\save results 
      } 
     } 
    }//implicit barrier here 
} 

를이 잘 작동하지만 의미 각각 실현 후 장벽이 있다는 것을 내가 병렬 블록 내에서 일을하고있는 물건이 더 이상 다른 사람보다 하나의 반복에 걸리는 경우, 모든 스레드는 다음 반복을 계속하는 대신 완료되기를 기다리고 있습니다.

스레드가 계속 작동하도록이 장벽을 피할 방법이 있습니까? 나는 수천 번의 반복을 평균하고있다. 따라서 더 많은 상처를 입지 않는다. (nit 변수가 이미 실행중인 스레드에서 증가하지 않은 경우) ...

나는 이것을 병렬로 바꾸려고 노력했다. for 루프가 자동으로 증가하면 nit 변수가 변경됩니다. 이것은 나의 시도 :

#pragma omp parallel shared(nit,avit) 
{ 
    #pragma omp for 
    for(nit=0;nit<avit;nit++){ 
     //do some stuff 
     if(condition){ 
      \\save results 
     } else { 
      #pragma omp critical 
      { 
       nit--; 
      } 
     } 
    } 
} 

그리고 예상대로 작동 및 루프의 주위에가는 유지하지만 하나가 다른 스레드에 의해 그것의 증가와 감소를 기대할 수 있기 때문에 내 nit 변수는 ... 예측할 수없는 값을 사용합니다 다른 시간에.

는 또한 빈 for 루프의 증가를 떠나려고했지만, 그 다음

... 
incr=0; 
for(nit=0;nit<avit;nit+=incr) 
... 

하지만 같은, 컴파일, 또는 루프의에는 증가가없는 내 코드를 속이려하지 않습니다 내 코드가 충돌합니다 ...

아이디어가 있으십니까?

감사

편집 : 여기에 while 루프의 코드의 작업 최소한의 예제는 :

#include <random> 
#include <vector> 
#include <iostream> 
#include <time.h> 
#include <omp.h> 
#include <stdlib.h> 
#include <unistd.h> 

using namespace std; 

int main(){ 

    int nit,dit,avit=100,t,j,tmax=100,jmax=10; 
    vector<double> Res(10),avRes(10); 

    nit=0; dit=0; 
    while(nit<avit){ 
     #pragma omp parallel shared(tmax,nit,jmax,avRes,avit,dit) private(t,j) firstprivate(Res) 
     { 
      srand(int(time(NULL))^omp_get_thread_num()); 
      t=0; j=0; 
      while(t<tmax&&j<jmax){ 
       Res[j]=rand() % 10; 
       t+=Res[j]; 
       if(omp_get_thread_num()==5){ 
        usleep(100000); 
       } 
       j++; 
      } 
      if(t<tmax){ 
       #pragma omp critical 
       { 
        nit++; 
        for(j=0;j<jmax;j++){ 
         avRes[j]+=Res[j]; 
        } 
        for(j=0;j<jmax;j++){ 
         cout<<avRes[j]/nit<<"\t"; 
        } 
        cout<<" \t nit="<<nit<<"\t thread: "<<omp_get_thread_num(); 
        cout<<endl; 
       } 
      } else{ 
       #pragma omp critical 
       { 
        dit++; 
        cout<<"Discarded: "<<dit<<"\r"<<flush; 
       } 
      } 
     } 
    } 
    return 0; 
} 

나는 다른 사람보다 오래 걸리는 하나 개의 스레드를 시뮬레이션 할 usleep 부분을 추가했다. 프로그램을 실행하면 모든 스레드가 스레드 5가 완료 될 때까지 기다린 후 다음 실행을 시작합니다. 내가 뭘하려고하는지 정확하게 기다리는 것을 피하는 것입니다. 즉, 다른 스레드가 5를 끝내기를 기다리지 않고 다음 반복을 선택하고 싶습니다. 또한 중요한 지역으로 작동

int nit = 0; 
#pragma omp parallel 
while(1) { 
    int local_nit; 
    #pragma omp atomic read 
    local_nit = nit; 
    if (local_nit >= avit) { 
      break; 
    } 

    [...] 

    if (...) { 
      #pragma omp critical 
      { 
       #pragma omp atomic capture 
       local_nit = ++nit; 
       for(j=0;j<jmax;j++){ 
        avRes[j] += Res[j]; 
       } 
       for(j=0;j<jmax;j++){ 
        // technically you could also use `nit` directly since 
        // now `nit` is only modified within this critical section 
        cout<<avRes[j]/local_nit<<"\t"; 
       } 
      } 
    } else { 
      #pragma omp atomic update 
      dit++; 
    } 
} 

을하지만, 아토 더 효율적입니다 :

+0

* 일부 항목 *에 대해 더 구체적으로 이해하지 않으면 질문에 올바르게 답변 할 수 없습니다. 특히 우리는 * 물건에 * 접근 할 수 있는지, 그리고 여러 스레드가 동시에 조건을 가지고있을 때 일어날 것인가, 아니면 하나의 스레드가 몇 가지 작업을하는 동안 여러 번 업데이트되는 것을 생각할 필요가 없습니다 * ... 어렵습니다. 그러나 훌륭하고 구체적인 답변을 위해서는 [mcve]를 만들어야합니다. – Zulan

+0

@Zulan 주석 주셔서 감사합니다. 끝에 최소한의 예제를 추가하기 위해 질문을 편집했습니다. 희망이 물건을 명확히합니다. –

답변

0

당신은 기본적으로 avRes 병렬로 기록되지 않도록 약간의 변화와 함께, this question와 동일한 개념을 따를 수 있습니다.

고려해야 할 또 다른 사항이 있습니다. rand()은 병렬 컨텍스트에서 사용해서는 안됩니다. this question을 참조하십시오. C++의 경우, <random>의 개인 (즉, 병렬 영역 내에 정의 된) 난수 생성 프로그램을 사용하십시오.

+0

@ Zulan에게 사소한 수정을 해 주셔서 (거의) 트릭을 수행하는 것 같습니다! 나는 '원자'에 익숙하지 않지만,'critical'처럼 코드 블럭을 추가 할 수는 없다. 모든 스레드가 결과를 쓸 수 있어야하고, 단지 더 자주 쓰여 져야한다. 끝 ... 만약 내가'#pragma omp critical {local_nit = nit ++; for (j = 0; j

+0

'원자'는 단 한 줄의 지시에만 사용할 수 있습니다. 따라서 최종 코드는 작성을위한 '임계'섹션을 가져야합니다. 그리고 마지막 수정과 마찬가지로'local_nit = nit ++;'는'#pragma omp atomic read local_nit = nit;'에'local_nit'가 업데이트되어''nit ++ ''가되어야한다고 생각합니다. 끝이 원하지 않을 때까지 글쓰기를 금지합니다. 다시 도움을 청합니다. –

+0

내 코드가 실수로 prefix 접미사 대신 postfix를 사용하고있었습니다. 나는 그것과 링크를 고쳤다. 올바른 형식의'local_nit = ++ nit; if (local_nit == avit) ... '값 비싼 크리티컬 섹션없이 출력물을 보호 할 수 있습니다. – Zulan