2. Advanced! 리눅스 네트워크 시스템 프로그래밍
김선영 저, 2판
가메출판사
책의 8장 스레드 프로그래밍
3. 무임승차했던 성능 문제
멀티스레딩과 성능 향상
병렬 처리 패턴
스레드 안전
pthread
OpenMP 프로그래밍
성능을 고려한 프로그래밍
4.
5. 인텔 CPU의 발전
80년대 초반 90년대 초반
반도체 미세 공정 능력 0.18㎛ 65㎚
트랜지스터 집적 능력 약 9.5M개 약 291M
클록(㎐) 500㎒ 3.2㎓
무어의 법칙
◦ 반도체의 회로 집적도는 2년마다 2배씩 증가
성능이 떨어지는 코드 하드웨어 교체로 개선
6. AMD 4㎓ CPU
◦ 매우 많은 전력 소모와 무자비한 발열
전산업계의 거품 현상
◦ 비용 소모(전력 등)는 투자 및 자금 유치로 해결
◦ 거품이 빠지면서 공황상태
Green IT, 모바일 시장의 발전
◦ 전력 절감만이 살길
8. 공정 기술의 향상으로 CPU에 복수 개의 코어 이식
◦ CMP(Chip Multi Processor), 내장 그래픽 등
I7입니다. 내용과 무관합니다
9. 성능이 비슷하거나 낮은 여러 개의 코어
◦ 병렬 처리, 비동기 처리 기법에 대한 연구 진행
◦ 단일 스레드 프로그램에서는 성능 저하 유발
I7입니다. 내용과 무관합니다
10. 책에서는 Thread Building Block 소개가 없습니다
pthread(POSIX thread)
◦ 최신 UNIX 커널은 대부분 지원
◦ 윈도우 native 스레드에 비해 성능이 떨어집니다
OpenMP
◦ 스레드 기법 몇가지를 단순화
◦ C/C++ portran 등 다양한 언어 지원
◦ #pragma omp로 직접 함수를 코딩하지 않아도 됩니다
◦ 전처리기 수준에서 처리하므로 높은 이식성 확보
◦ GCC/MSC 지원
11.
12. 단일 CPU 에서의 처리 방법
Task #1 Task #2
멀티코어 CPU에서의 병렬 처리 방법
Task #1
Task #2
단일 CPU에서의 동시 처리 방법
Task #1
Task #2
13. Latency
◦ 요청 후 실제 응답이 오기까지 걸리는 대기 시간
◦ CPU가 다른 장치에 비해 매우 빠르므로 생기는 시간
Latency 중 CPU에서 다른 스레드의 작업을 처리
◦ I/O를 비동기로 처리하므로 Latency Hiding 가능
I/O Response
& processing
wait wait
I/O Request
14. 프로그램의 성능 향상을 위한 I/O 및 저장장치 접
근 최소화를 위한 두가지 방법
Multi Thread
◦ 프로세스 내부 처리 구조를 Multi Process처럼 분업화
◦ 스레드 간 통신에 따른 비용 소모가 거의 없음
◦ 스레드 간 동기화 처리 비용 소모
Multi Process
◦ 동기적 프로그래밍 모델
◦ 보호되는 자원(메모리, 장치 등)
◦ 프로세스간 통신에 따른 비용 소모(IPC 등)
15. Multi Process
Process Process
copy copy
IPC
Multi Thread process
Thread Thread
Data
16. 멀티 스레딩은 최후의 보루입니다
◦ 개발, 테스트, 디버깅이 복잡해집니다
◦ 설계나 개발 단계에서 예측하지 못한 상황에 빠질 가능성
이 있습니다
◦ “프로그래머가 관찰을 위해 개입하는 순간, 비결정적인
결과를 나타내어 버그가 사라지는 현상”
17. 고려 사항
◦ I/O 측면에서 병목(bottleneck)이 제거된 상태인가?
◦ 멀티 스레드 도입 전의 코드는 다른 최적화 방법을 적용
해 보았는가?
◦ 멀티 스레드 도입 전의 시스템에 가용할 수 있는 CPU나
관련 유휴 자원은 충분한가?
◦ 효율을 극대화하려면 스레드의 숫자를 어떻게 결정해야
하는가?
18.
19. 대분류에 속하는 패턴입니다
태스크 분해(Task Decomposition)
◦ 작업의 단위나 순서의 흐름이 중요한 경우
데이터 분해(Data Decomposition)
◦ 작업할 데이터의 형태나 크기가 중요한 경우
20. 처리해야 하는 데이터나 행위가 매번 달라지거나,
연속적인 흐름을 띄는 경우에 적합
콜백, 트리/파면 분기, 파이프라인 등
◦ 웹 브라우저에 적용
병렬 처리를 위해 분해된 태스크들을 스레드가 실
행하는 형태
◦ 규모에 따라 태스크 하나에 하위 스레드 여러 개 할당
◦ 선후관계/의존성에 따른 동기화 처리 요구(배리어 등)
21. 트리 구조의 태스크
Task
Task Task Task
Task
Task
Task
파이프라인 구조의 태스크
Data Data Data Data Data Data Data Data
Task #1 Task #2 Task #3
22. 동일하거나 비슷한 작업을 하는 복수의 태스크 생성
데이터 인코딩/디코딩, 대규모 계산 등에 사용
◦ 압축, 이미지 프로세싱, 행렬 계산 등
적절한 부하 분산(Load Balancing) 요구
◦ 데이터를 적절한 단위(chunk)로 분할하여 작업 할당
load thread thread
balancing
chunk chunk chunk chunk
decomposition chunk chunk chunk chunk
Data chunk chunk
chunk chunk
thread thread
chunk chunk
chunk chunk
23. 병렬 처리에 루프를 주로 사용하는 경우 데이터 분
해 방식 적합
분기 혹은 데이터 부분 가공인 경우 태스크 분해
방식 적합
필요에 따라 복합적으로 사용합니다
로컬 임시파일/결과 복사
partitioner file 1-1
map
1 file 1-2
block 1 reduce 1
file 2-1
대용량 데이터 block 2
map
2 file 2-2
분석 프레임워크 block 3
map file 3-1 output 1
병합/정렬
맵리듀스 구조
3 file 3-2
block 4 file 4-1
map reduce 2
4 file 4-2
block 5
map file 5-1
5 output 2
file 5-2
24.
25. 스레드에서 사용해도 안전한 코드의 총칭
◦ 스레드에서 사용해도 안전하게 수행되는 코드
◦ 주로 함수에 대해 안전한지 판단합니다
UNIX 계열에서는 스레드 안전에 대해 상세 분류
◦ 재진입, 병렬 처리, 시그널 처리에 대한 안전 여부 등
◦ 스레드 안전 개념의 혼란 초래
유닉스 표준(SUSv4)에서 용어 가지치기 단행
◦ 용어와 개념, 그리고 잔재들을 소개하는 절입니다
26. static char buf_sum[16]; 이 함정
지역 변수로 만들어 해결하면 되지만 예제이므로
상황을 복잡하게 만듭니다
30. 병렬 실행을 보장하도록 작성된 형태를 취햐여 스
레드 안전을 획득한 경우
같은 프로세스 내에서 재귀 호출되어도 문제 없음
재진입성이 없는 표준 함수들
◦ strtok, ctime, gethostbyname, rand, srand, …
◦ _r로 끝나는 함수는 안전합니다(UNIX)
최신 유닉스 표준(SUSv4)에서 재진입성은 스레드
안전에 포함되는 개념으로 편입시켜 정의
31. 재진입은 정적 객체를 사용하는 경우나 극히 제한
적인 코드에만 적용 가능
전역 변수의 경우 뮤텍스를 통해 스레드 안전 확보
공유 자원에 락을 걸면 안됩니다
◦ 네트워크, 파일 입출력 등
◦ 부분 입출력 후 스위칭되는 경우 기아 유발
◦ Isolated I/O 사용(IOCP 등)
32. worker
thread 뮤텍스로 보호되는 구간
worker
thread output
큐 network
worker send 등록 send thread
thread 작업 꺼내기
worker
thread
33. 함수 실행 중 시그널에 의한 인터럽트 발생
EINTER 오류 반환(Error Interrupt)
◦ 멀티스레드 환경에서 lock 함수 호출 도중 시그널 발생 등
◦ 세마포어 lock 시도 시그널 안전하지 않음
◦ 세마포어 unlock 시도 시그널 안전
스레드 취소 함수(pthread_cancel)시 수행중인 함
수가 정상 종료하는 경우 비동기 취소 안전
34. 저수준 입출력(read, write)는 버퍼(PIPE_BUF)보다
입출력이 작은 경우 실행 보장
sig_atomic_t 정수형 변수의 접근 보장
대부분의 함수는 원자적 실행을 보장하지 않습니다
35. 입출력 구간을 나누어 스레드마다 구간 입출력
write() pwrite() 사용
POSIX Realtime Extension의 AIO 사용
36.
37. pthread는 전통적인 API 스펙이므로 한번 익혀두
면 오랫동안 별 탈 없이 사용할 수 있습니다
기능별 세분화가 잘 되어있음
◦ 복잡합니다
오류 처리 방법
◦ 성공시 0 반환, 실패시 오류 코드 반환
◦ errono 전역변수 공유 회피
시그널 처리에 의해 인터럽트되지 않습니다
◦ 비동기 시그널 함수는 인터럽트 됩니다
38. Windows Native thread와 비슷합니다
pthread_create 스레드 생성
pthread_exit 스레드 종료
pthread_join 스레드를 프로세스에 병합
pthread_detach 스레드를 프로세스에서 분리
pthread_cancel 스레드 취소
pthread_create(pthread_t *restrict_thread,
const pthread_attr_t *restrict_attr, void
*(*start_routine)(void *), void *restrict_arg);
pthread_join/pthread_detach
◦ join은 스레드 대기, detach는 스레드 제어 포기
39. pthread_exit의 반환 주소는 스레드 스택에 두면
안됩니다
◦ 스레드 스택이 파괴되면 반환 주소가 날아가면서
pthread_join으로 대기할 수 없습니다
pthread_cancel은 강제 종료가 아닙니다
◦ 스레드 중지 요청(deferred cancel, 지연된 취소)
◦ 스레드는 특정 지점마다 중지 요청이 있는지 확인 후 중지
◦ 공유 메모리, 자원 등 누수 가능성 존재
pthread_mutex_timedlock
◦ lock + 타임아웃
◦ 타임아웃 시간 이후 오류를 반환합니다
40. Win32의 그것과 매우 흡사합니다
◦ waitfor- 함수 대신 lock & unlock 함수 사용
◦ try, timeout 함수 제공
◦ 객체의 생성, 뮤텍스 획득, 해제, 파괴 함수 제공
뮤텍스 속성
◦ pthread_mutexattr_settype(*attr, type)
normal errcheck recursive
재귀 잠금 허
중복 잠금 교착 상태 오류 반환
용(횟수 적용)
오류 반환 오류 반환
소유권이 없는 잠금 해제 시도 undefined
(EPERM) (EPERM)
오류 반환 오류 반환
풀린 뮤텍스에 잠금 해제 시도 undefined
(EPERM) (EPERM)
성능 빠름 약간 느림 약간 느림
41. 스레드가 특정 조건을 만족할 때까지 대기
thread B
lock mutex
item 준비
thread A 뮤텍스
영역 큐 확인
lock mutex
yes no
조건 변수 블록
item 큐잉 조건 (unlock mutex)
변수
영역 조건 변수에서 깨어남
unlock mutex (lock mutex)
thread B에 signal item 디큐잉
시그널 전송 전송
unlock mutex
42. 조건 변수에 의해 대기하는 경우 뮤텍스 해제
◦ 기아 방지
조건 변수에서 깨어나는 경우 즉시 조건 검사를 해
야 합니다
◦ 복수의 스레드가 깨어나는 경우 경쟁 상태 유발
조건 변수 관련 함수 & 매크로
pthread_cond_init 조건 변수 초기화
pthread_cond_wait 조건 변수 대기
pthread_cond_timedwait 대기후 타임아웃 지정
(지정 시간 후 오류 반환)
pthread_cond_signal 스레드 하나를 깨움
pthread_cond_broadcast 스레드 집합을 깨움
pthread_cond_destroy 조건 변수 파괴
PTHREAD_COND_INITIALIZER 선언 및 초기화에 사용하는 매크로
43. 뮤텍스와 조건 변수는 공유 메모리에 둡니다
프로세스 공유 속성 함수
pthread_mutexattr_setpshared 뮤텍스 속성에 프로세스 공유 기능 설정
pthread_mutexattr_getpshared 뮤텍스 속성의 프로세스 공유 기능 반환
pthread_condattr_setpshared 조건 변수 속성에 프로세스 공유 기능 설정
pthread_condattr_getpshared 조건 변수 속성의 프로세스 공유 기능 반환
매개변수
◦ pthread_mutexattr_t : 뮤텍스 속성
◦ pthread_condattr_t : 조건 변수 속성
◦ int pshared : PTHREAD_PROCESS_SHARED,
PTHREAD_PROCESS_PRIVATE
44. 스레드들이 특정 코드 지점에 모일 때까지 대기
POSIX.1003.2-2001에 추가됨
◦ _XOPEN_SOURCE 매크로가 600 이상이면 됩니다
배리어 함수들
배리어 객체 초기화
pthread_barrier_init(count)
(count만큼 wait 호출 전까지 스레드 대기)
pthread_barrier_destroy 배리어 객체 파괴
pthread_barrier_wait 다른 스레드 도착 대기
pthread_barrierattr_init 배리어 속성 객체 초기화
pthread_barrierattr_destroy 배리어 속성 객체 파괴
pthread_barrierattr_getpshared 배리어 공유 속성 확인
pthread_barrierattr_setpsahred 배리어 공유 속성 설정
46. 공유 자원에 여러 스레드가 효율적으로 접근
reader-lock이 걸린 경우 writer-lock은 잠깁니다
위의 함수 원형들과 형태가 비슷합니다
◦ pthread_rwlock_init / destroy
◦ rwlock_rdlock / wrlock
◦ try__lock, timed__lock
프로세스 공유 속성은 지원하지 않습니다
47. Win32의 그것과 비슷합니다
GCC에서는 __thread 예약어 제공
스레드 안전한 함수를 작성할 때 유용합니다
int pthread_key_create(pthread_key_t *key, void
(*destructor)(void *));
◦ 파괴자 함수를 직접 지정할 수 있습니다
기타
◦ pthread_key_delete(key)
◦ pthread_setspecific(key, value)
◦ value pthread_getspecific(key)
48. Win32 뮤텍스의 WAIT_ABANDONED_0
◦ 뮤텍스가 잠긴 채 스레드가 죽었습니다
◦ pthread에서는 EOWNERDEAD 오류 반환
잠긴 뮤텍스를 자동으로 다른 스레드가 받음
◦ pthread_mutexattr_(set/get)robust(attr, int robust)
◦ robust 값
PTHREAD_MUTEX_STALLED : 교착 상태
PTHREAD_MUTEX_ROBUST : 다른 스레드가 뮤텍스를 받음
◦ 뮤텍스를 받은 스레드는 뮤텍스 인계 함수 호출
pthread_mutex_consistent
처리하지 않는 경우 lock 함수 실패, ENOTRECOVERABLE
반환
49. WndProc이 아닙니다
스레드 종료 / fork() 호출 등 예외 이벤트 처리용
◦ fork() 이전에 비동기 작업을 정지하거나 제거
스레드 클린업 핸들러
◦ 스레드가 종료될 때 실행하는 함수 등록
◦ atexit() 함수의 스레드 버전
◦ 핸들러에 등록된 이벤트는 스택처럼 쌓입니다
pthread_cleanup_push(routine, arg)
pthread_cleanup_pop(n) : 0 or ~0
~0이면 클린업 핸들러 실행 후 제거, 0이면 바로 제거
50. 스레드 fork 핸들러
◦ pthread_atfork(prepair, parent, child)
prepair는 fork() 이전에 실행할 함수
parent는 fork() 호출 이후 부모 프로세스가 실행할 함수
child는 fork() 호출 이후 자식 프로세스가 실행할 함수
◦ fork()를 호출하는 스레드만 복제됩니다
다른 스레드는 복제되지 않습니다
복잡해지므로 fork()를 사용하지 않는 것을 권장합니다
51.
52. 간단한 지시어를 사용하여 멀티스레딩을 적용할 수
있는 기법
이식성이 높고 학습 용이
코드 수정을 최소화하고 멀티스레딩 적용 시간 단축
짧은 역사(1996~)
다양한 언어(C/C++, Fortran 등) 지원
#define _OPENMP 매크로 정의됨
53. OpenMP 3.0 코드는 실행이 불가능합니다
◦ visual studio 2012에서 OpenMP 3.0을 지원하지 않습
니다
◦ Intel Parallel Studio 설치시 지원 가능합니다($1,599)
◦ 해봤더니 안됩니다 ㅠㅠ
55. 기본 OMP 스레드 수 == CPU 수
#pragma omp … num_threads(n)
◦ 한번 적용
omp_set_num_threads(n)
◦ 함수입니다
◦ 호출 이후 OpenMP 스레드를 자동으로 n만큼 만듭니다
56. loop 모델 루프 작업을 분할하여 병렬 처리
직렬 코드 블록들을 몇 개의 구간으로 분할
sections 모델
워크 쉐어링 구조 하여 병렬 처리
병렬 처리되는 구간회서 1회성 실행 구간
single 모델
설정
태스크 구조 task 모델(3.0) 태스크 단위 작업을 처리하는 스레드 생성
57. OpenMP 병렬 구간에서 변수의 공유 설정
private(list) list에 지정된 변수를 TLS에 생성
사설(private) firstprivate(list) list를 main 스레드의 초기화값으로 초
속성 기화
마지막 스레드의 해당 변수 값을 main
lastprivate(list)
스레드에 반영
명시적으로 모든 스레드가 공유하는 변
공유 속성 shared(list)
수로 선언
value : shared, none
기본 설정 default(value) 변수의 공유 설정 기본값, parallel 병
렬 구간이 시작할 때 설정
58. reduction(operand:var)
◦ var 값에 operand 연산자 수행
◦ 내부에서 묵시적으로 private 지시어 수행
default가 none일 경우 명시적으로 shared로 선언
reduction 연산
연산자 초기값 연산자 초기값
+ 0 & ~0
* 1 | 0
- 0 && 1
^ 0 || 0
max 표현 가능한 최소값 min 표현 가능한 최대값
59.
60. 루프는 반복 횟수가 정해져 있어야 함
#pragma omp parallel 이후 문장부터 스레드 생
성
for문 반복 횟수 == 분할 개수 * 스레드 수
모든 스레드가 완료할 때까지 대기(묵시적 배리어)
#pragma 두 줄
◦ 합쳐서 기술 가능
◦ #… parallel for
omp_get_thread_num()
◦ 스레드 번호 반환
61. main()
#pragma omp parallel
#pragma omp for
i = 0 i = 4
i = 1 i = 5
i = 2 i = 6
i = 3 i = 7
/* implicit barrier */
62. 남는 스레드가 밀린 작업을 하도록 작업 할당
schedule(static [, n]) 라운드 로빈 방식으로 순서대로 n개씩 할당. n
생략시 1
schedule(dynamic [, n]) 한가한 스레드에게 n개씩 할당. n 생략시 1
schedule(guided [, n]) dynamic과 동일하게 한가한 슬데ㅡ에게 할당
하지만 chunk의 크기가 다름. 할당되는 chunk
크기는 큰 수에서 n까지 줄여나감. n 생략시 1
schedule(auto) 임플리먼테이션이 자동으로 판단
schedule(runtime) 실행시 ICV 환경 변수에 의해 결정
63. dynamic 스케줄링은 개별 작업의 수행 시간이 균
일하지 못할 때 좀 더 빨리 작업을 끝낸 스레드에
게 새로운 chunk 할당
static, dynamic 스케줄링은 chunk 크기가 작은
경우 오버헤드 유발
guided는 chunk 크기를 점점 줄여 나가며 할당
◦ 전체적으로 스케줄링 횟수가 줄어듦
runtime에 쓰이는 OpenMP 내부 제어 변수
(OpenMP ICV)은 환경 설정 변수나 함수 호출로
설정 가능
64. 스레드 작업 순서를 정렬하여 결과를 순서대로 작
성
직렬화/동기화 기법을 직접 구현하는 것보다 성능
향상
65. 코드의 특정 구간을 다수의 섹션으로 분할하여 병
렬 처리하는 태스크 방식
main()
#pragma omp parallel
#pragma omp sections
section section
#1 #2
/* implicit barrier */
66. 임의의 섹션을 임의의 스레드가 수행
◦ 수행 순서는 보장되지 않음
변수 공유 및 환원 가능
67. single 블록은 한번만 수행
스레드 중 가장 먼저 진입하는 스레드가 수행
◦ 나머지 스레드들은 single 작업이 끝날 때 까지 대기
주로 초기화 작업 등에 사용
main()
#pragma omp parallel
single
/* implicit barrier */
parallel parallel
#1 #1
/* implicit barrier */
68. 특정 작업 단위로 분할된구간을 스레드에게 할당
임의의 구간을 임의의 스레드가 수행
루프의 개수, 중첩 여부, 재귀 여부에 관계없이 활
용 가능
task thread
code #1
task task task task thread
code code code code #2
task thread
code #n
69. 현재 스레드(주로 메인 스레드)가 작업 코드에 해
당하는 구간을 스레드에게 분배
if
◦ 스레드가 작업을 분배할 조건을 설정
◦ 특정 시점부터 분배를 시작하게 할 수 있습니다
◦ #pragma omp ~ if(exp)
70. untied
◦ 스레드가 정지 후 재시작(suspeded resume)될 때 다
른 스레드가 작업을 이어 받도록 설정
◦ tied인 경우 재시작 이후에도 같은 스레드가 작업(기본값)
71. 배리어, 크리티컬 섹션, 원자적 실행, OpenMP
lock 제공
크리티컬 섹션은 Win32의 그것과 다를 수 있음
OpenMP lock은 뮤텍스와 유사
72. parallel, for, sections, single의 끝에는 묵시적
배리어가 존재
명시적 배리어
◦ #pragma omp barrier
◦ #pragma omp taskwait
자식 task 대기 조건문과 결합하는 경우
묵시적 배리어 제거
◦ #pragma omp ~ nowait
◦ loop, sections, single에 사용
#pragma omp critical [name]
◦ name을 생략하면 이름이 없는 것으로 간주
73. #pragma omp atomic [read | write | update |
capture]
◦ 생략시 update로 간주
atomic 형식 분류(x : 대상)
read v = x; v는 TLS 변수
write x = exp; exp는 보호되지 않음
x++;
대상이 변하면서 읽어야 하는 경우
x--;
사용
update ++x;
--x;
축약 대입 연산 가능
x binary_operator = exp;
v = x++;
v = x--; update + read
capture v = ++x; 공유 데이터를 변경하고 값을 읽어야
v = --x; 하는 다수의 작업에 적합
v = x binary_operator = exp;
79. #pragma omp threadprivate(list)
◦ 리스트에 있는 변수를 TLS 변수로 선언
◦ 원본 변수는 정적 변수
◦ 예제는 길어서 생략합니다
TLS 변수의 복사
◦ 원본은 마스터 스레드
◦ TLS 변수 중 일부만 복사 가능
◦ #pragma omp parallel copyin(list)
병렬 구간이 시작될 때 TLS 변수 복사
◦ #pragma omp single copyprivate(list)
single 코드 블록이 끝나면서 TLS 변수 복사
80. Internal Control Variable의 약자입니다
스레드 개수 관련 ICV
생성할 스레드의 개수 설정
환경 변수 OMP_NUM_THREADS=n[, …]
중첩 단계별로 „,‟로 구분
omp_set_num_threads(n) 생성할 스레드의 개수 설정
omp_get_num_threads() 현재 스레드 개수 제한
함수
omp_get_max_threads() 현재 최대 스레드 개수 제한
omp_get_team_size() 중첩 단계
81. 중첩 관련 ICV
환경 변수 OMP_NESTED value : true or false
omp_set_nested(value) value : 0 or ~0
함수 omp_get_nested() 0 or ~0 반환
omp_get_level 현재 병렬화 중첩 단계 반환
스케줄링 관련 ICV (스케줄링 방법이 runtime인
경우)
OMP_SCHEDULE=type [, type : static, dynamic,
환경 변수
chunk] guided, auto
omp_set_schedule(omp_sch kind : 스케줄 방법
함수 ed_t kind, int modifier) modifier : chunk 개수
int omp_get_schedule() 현재 스케줄링 방법
82. schedule(static [, n]) 라운드 로빈 방식으로 순서대로 n개씩 할당. n
생략시 1
schedule(dynamic [, n]) 한가한 스레드에게 n개씩 할당. n 생략시 1
schedule(guided [, n]) dynamic과 동일하게 한가한 슬데ㅡ에게 할당
하지만 chunk의 크기가 다름. 할당되는 chunk
크기는 큰 수에서 n까지 줄여나감. n 생략시 1
schedule(auto) 임플리먼테이션이 자동으로 판단
schedule(runtime) 실행시 ICV 환경 변수에 의해 결정
83. 동적 조정 관련 ICV (실행 중 스레드 개수 조정)
환경 변수 OMP_DYNAMIC=value value : true or false
omp_set_dynamic(value) value : 0 or ~0
함수
omp_get_dynamic() 동적 조정 여부 반환
기타
과거 특정 시점부터 흐른 시
double omp_get_wtime()
함수 간(time처럼 쓰입니다)
double omp_get_wtick() ↑의 정밀도(단위) 반환
omp_get_wtime()은 부팅 이후도 반환할 수 있음