2012-11-17 6 views
7
Node *head = &node1; 
while (head) 
{ 
    #pragma omp task 
     cout<<head->value<<endl; 
    head = head->next; 
} 

#pragma omp parallel 
{ 
    #pragma omp single 
    { 
     Node *head = &node1; 
     while (head) 
     { 
      #pragma omp task 
       cout<<head->value<<endl; 
      head = head->next; 
     } 
    } 
} 

첫 번째 블록에서는 병렬 지시문없이 태스크를 작성했지만 두 번째 블록에서는 병렬 지시문과 단일 지시문을 사용했습니다. 이는 필자가 종이에서 본 일반적인 방법입니다. 그들 사이의 차이점은 무엇입니까? BTW, 나는이 지시어의 기본적인 의미를 안다.OpenMP 태스크와 병렬 실행 및 병렬 실행

내 댓글의 코드 :

void traverse(node *root) 
{ 
    if (root->left) 
    { 
     #pragma omp task 
     traverse(root->left); 
    } 
    if (root->right) 
    { 
     #pragma omp task 
     traverse(root->right); 
    } 
    process(root); 
} 

답변

12

의 차이는 첫 번째 블록 당신이 블록 자체가 활성 내부 (도 구문이나 어휘) 중첩되지 않기 때문에 정말 어떤 작업을 생성하지 않은 것입니다 평행 영역. 두 번째 블록에서 task 구조는 문법적으로 parallel 영역 내에 중첩되어 있으며 영역이 런타임에 활성 상태 인 경우 명시 적 작업을 대기열에 넣습니다 (활성 병렬 영역은 둘 이상의 스레드로 구성된 팀과 함께 실행됩니다). 사전 적 중첩은 덜 명확합니다. 다음 예를 살펴 :

void foo(void) 
{ 
    int i; 

    for (i = 0; i < 10; i++) 
     #pragma omp task 
     bar(); 
} 

int main(void) 
{ 
    foo(); 

    #pragma omp parallel num_threads(4) 
    { 
     #pragma omp single 
     foo(); 
    } 

    return 0; 
} 
foo()

처음 호출 모든 병렬 영역 밖에서 일어난다. 따라서 task 지시문은 (거의) 아무것도 수행하지 않고 bar()에 대한 모든 호출이 연속적으로 발생합니다. foo()에 대한 두 번째 호출은 병렬 영역 내부에서 이루어 지므로 foo() 내부에 새 작업이 생성됩니다. parallel 영역은 스레드 수가 4으로 고정되었으므로 num_threads(4) 절에 의해 활성화됩니다.

OpenMP 지시문의 이러한 다른 동작은 디자인 기능입니다. 주요 아이디어는 직렬 및 병렬로 실행할 수있는 코드를 작성하는 것입니다.

여전히 foo()task 구조체가 존재하면 코드 변환이 약간 수행된다. 여기 OMP_make_task()

void foo_omp_fn_1(void *omp_data) 
{ 
    bar(); 
} 

void foo(void) 
{ 
    int i; 

    for (i = 0; i < 10; i++) 
     OMP_make_task(foo_omp_fn_1, NULL); 
} 

는 첫 번째 인수로 제공되는 함수에 대한 호출을 큐잉 OpenMP를 지원 라이브러리에서 가상의 (공개되지 않음) 함수 : foo()은 같은 것으로 변환된다. OMP_make_task()이 감지되면 액티브 병렬 영역 외부에서 작동하지만 대신 foo_omp_fn_1()을 호출합니다. 이로 인해 일련의 경우 bar() 호출에 약간의 오버 헤드가 추가됩니다. main -> foo -> bar 대신 main -> foo -> OMP_make_task -> foo_omp_fn_1 -> bar과 같이 호출됩니다. 이것은 직렬 코드 실행 속도가 느리다는 것을 의미합니다.

이는 더욱 분명 작업 공유 지시자로 설명된다

void foo(void) 
{ 
    int i; 

    #pragma omp for 
    for (i = 0; i < 12; i++) 
     bar(); 
} 

int main(void) 
{ 
    foo(); 

    #pragma omp parallel num_threads(4) 
    { 
     foo(); 
    } 

    return 0; 
} 

foo()에 대한 첫 번째 호출은 일련의 루프를 실행됩니다. 제 2 호출은 4 개의 스레드 사이에 12 개의 반복을 분배 할 것이다. 즉, 각 스레드는 3 개의 반복만을 실행할 것이다. 다시 한번,이를 달성하기 위해 일부 코드 변환 마법이 사용되며 이 존재하지 않는 경우보다 foo()에 직렬 루프가 느리게 실행됩니다.

여기서 교훈은 실제로 필요하지 않은 OpenMP 구문을 절대 추가하지 않는 것입니다.

+0

+1 좋은 답변입니다. – dreamcrash

+0

나는 작업의 사용에 실수를 한 것으로 보인다.이 문제는 내가 질문에서 추가 한대로 단지 "작업"으로 트리를 재귀 적으로 가로 지르는 코드를 보았 기 때문에 발생했습니다. 나는 그것이 호출되는 곳에서 "병렬"과 "단일"이 트래버스 기능을 둘러싸도록해야한다고 생각합니다. 진심으로 감사드립니다. –

+0

@AnnieKim, 예, 질문에 표시된'traverse()'함수는 활성'parallel' 영역 내에서 호출 된 경우 병렬로 트리를 트래버스하고 그렇지 않은 경우 연속적으로 트래버스합니다. 그것은 OpenMP의 장점입니다. (오버 헤드가 추가 되었음에도 불구하고) –