
저번 글에 이어서 몇 가지 더 사용법 정리.
사용법
1. omp single
#pragma omp single // 하나의 thread만 실행한다. 다른 thread는 기다린다.
#pragma omp single nowait // 하나의 thread만 실행한다. 다른 thread는 기다리지 않는다.
하나의 쓰레드만 동작하게 한다. 초기화나 출력부처럼 병렬 처리가 필요 없는 부분에서 용이하다.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
int sum; | |
#pragma omp parallel | |
{ | |
// 초기화는 하나의 thread만 해도된다. | |
#pragma omp single nowait | |
{ | |
sum = 0 ; | |
} | |
#pragma omp for | |
for(int i = 0 ;i < 10 ;i++) | |
{ | |
printf("thread %d calc sum\n", omp_get_thread_num()); | |
#pragma atomic | |
sum += i; | |
} | |
// 출력은 하나의 thread만 해도된다. | |
#pragma omp single | |
{ | |
printf("thread %d init sum : %d\n", omp_get_thread_num(), sum); | |
} | |
// 다시 병렬로 작업을 한다. | |
printf("thread %d done\n", omp_get_thread_num()); | |
} | |
/* | |
thread 0 calc sum | |
thread 0 calc sum | |
thread 0 calc sum | |
thread 2 calc sum | |
thread 2 calc sum | |
thread 3 calc sum | |
thread 3 calc sum | |
thread 1 calc sum | |
thread 1 calc sum | |
thread 1 calc sum | |
thread 0 init sum : 45 | |
thread 0 done | |
thread 3 done | |
thread 2 done | |
thread 1 done | |
*/ |
2. omp master
#pragma omp master // master thread만 실행한다. 다른 thread는 기다리지 않고 넘어간다.
single과 매우 유사하지만 master thread 하나만 동작한다. 또한, 다른 쓰레드는 기다리지 않고 다음 부분을 실행한다.
3. omp task
#pragma omp task // thread 하나에 task를 넘겨주고 넘어간다.
다음에 오는 코드를 다른 하나의 thread에 넘겨주고 넘어간다.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const int N = 10; | |
int partialSum[N] ={0,}; | |
#pragma omp parallel shared(partialSum) | |
#pragma omp single | |
{ | |
for (int i = 0 ; i < N ; i++) | |
{ | |
#pragma omp task // 쓰레드 하나에 다음 job을 던져주고 넘어간다. | |
{ | |
partialSum[i] = do_something(i * 1000); | |
printf("thread %d partial sum : %d\n", omp_get_thread_num(), partialSum[i]); | |
} | |
} | |
int totalSum = 0; | |
for (int i = 0 ; i < N ; i++) | |
totalSum += partialSum[i]; | |
printf("thread %d total sum : %d\n", omp_get_thread_num(), totalSum); | |
} | |
/* | |
// task를 기다리지 않기 때문에 partialSum이 계산 되기전에 total sum이 계산 되어버린다. | |
thread 17 total sum : 0 | |
thread 1 partial sum : 0 | |
thread 4 partial sum : 4953750 | |
thread 6 partial sum : 34881906 | |
thread 12 partial sum : 29962675 | |
thread 13 partial sum : 9817987 | |
thread 22 partial sum : 39995308 | |
thread 2 partial sum : 15164899 | |
thread 23 partial sum : 20087192 | |
thread 20 partial sum : 24987327 | |
thread 11 partial sum : 45058713 | |
*/ |
4. omp taskwait
#pragma omp taskwait // 이전에 발생된 task가 모두 완료되고 난뒤 다음 행에 진입한다.
task들이 모두 완료될 때까지 동기화가 필요할 때가 있다. 그럴 때 taskwait를 써서 완료되지 않은 thread를 기다려 줄 수 있다.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const int N = 10; | |
int partialSum[N] ={0,}; | |
#pragma omp parallel shared(partialSum) | |
#pragma omp single | |
{ | |
for (int i = 0 ; i < N ; i++) | |
{ | |
#pragma omp task | |
{ | |
partialSum[i] = do_something(i * 1000); | |
printf("thread %d partial sum : %d\n", omp_get_thread_num(), partialSum[i]); | |
} | |
} | |
#pragma omp taskwait // 위에서 생성된 task가 모두 종료 될 때까지 기다린다. | |
int totalSum = 0; | |
for (int i = 0 ; i < N ; i++) | |
totalSum += partialSum[i]; | |
printf("thread %d total sum : %d\n", omp_get_thread_num(), totalSum); | |
} | |
/* | |
thread 4 partial sum : 0 | |
thread 19 partial sum : 9989625 | |
thread 23 partial sum : 4944948 | |
thread 12 partial sum : 20006788 | |
thread 3 partial sum : 25184388 | |
thread 0 partial sum : 15051329 | |
thread 6 partial sum : 30223360 | |
thread 21 partial sum : 45053433 | |
thread 1 partial sum : 35240305 | |
thread 15 partial sum : 39894532 | |
thread 21 total sum : 225588708 // 이상없이 total sum이 출력된다. | |
*/ |
5. omp barrier
#pragma omp barrier // 모든 thread가 barrier에 도착한 후 이후 라인을 실행한다.
딥러닝 같이 task들의 stage가 명확하게 구분되어있고 이전 stage가 완료되어야만 다음 stage를 실행할 수 있는 경우 barrier로 먼저 끝난 thread를 기다리게 할 수 있다.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void do_precondition() | |
{ | |
printf("thread %d do precondtition\n", omp_get_thread_num()); | |
} | |
void do_main_work() | |
{ | |
printf("thread %d do main work\n", omp_get_thread_num()); | |
} | |
void do_job() | |
{ | |
do_precondition(); // 모든 thread가 precondition을 실행한 후 | |
#pragma omp barrier | |
do_main_work(); // main work 를 실행한다. | |
} | |
int main() | |
{ | |
#pragma omp parallel for num_threads(4) | |
for(int i = 0; i < 4; i++) | |
do_job(); | |
return 0; | |
} | |
/* | |
thread 0 do precondtition | |
thread 2 do precondtition | |
thread 3 do precondtition | |
thread 1 do precondtition | |
thread 1 do main work | |
thread 3 do main work | |
thread 0 do main work | |
thread 2 do main work | |
*/ |
Reference
데이터 동기화나 task 쪽에 자주 쓰는 것들을 정리해보았다.
'Programming > C | C++' 카테고리의 다른 글
STL - Vector 삽입/삭제/정렬/복사 등 사용법 예제 (0) | 2021.03.10 |
---|---|
OpenMP(1) - 입문자용 주요 사용법 간단한 설명/정리(omp parallel, for, atomic,critical) (3) | 2020.07.24 |
댓글