OpenMP 절
OpenMP API에 사용되는 절에 대한 링크를 제공합니다.
Visual C++는 다음 OpenMP 절을 지원합니다.
일반 특성의 경우:
절 | 설명 |
---|---|
if | 루프를 병렬 또는 직렬로 실행할지 여부를 지정합니다. |
num_threads | 스레드 팀의 스레드 수를 설정합니다. |
ordered | 순서가 지정된 지시문을 루프에서 사용하는 경우 문에 대한 병렬에 필요합니다. |
schedule | for 지시문에 적용됩니다. |
nowait | 지시문에서 암시적 장벽을 재정의합니다. |
데이터 공유 특성의 경우:
절 | 설명 |
---|---|
private | 각 스레드에 변수의 자체 인스턴스가 있어야 하며 |
firstprivate | 각 스레드에 고유한 변수 인스턴스가 있어야 하며 변수가 병렬 구문 앞에 존재하기 때문에 변수 값을 사용하여 초기화되도록 지정합니다. |
lastprivate | 바깥쪽 컨텍스트의 변수 버전이 최종 반복(for-loop 구문) 또는 마지막 섹션(#pragma 섹션)을 실행하는 스레드의 프라이빗 버전과 동일하게 설정되도록 지정합니다. |
shared | 하나 이상의 변수를 모든 스레드 간에 공유되도록 지정합니다. |
default | 병렬 영역에서 범위가 지정되지 않은 변수의 동작을 지정합니다. |
reduction | 각 스레드에 대해 비공개인 하나 이상의 변수가 병렬 영역의 끝에 있는 감소 작업의 대상이 되도록 지정합니다. |
copyin | 스레드가 threadprivate 변수에 대해 주 스레드의 값에 액세스할 수 있도록 허용합니다 . |
copyprivate | 하나 이상의 변수를 모든 스레드 간에 공유되도록 지정합니다. |
copyin
스레드가 threadprivate 변수에 대해 주 스레드의 값에 액세스할 수 있도록 허용합니다 .
copyin(var)
매개 변수
var
threadprivate
병렬 구문 앞에 있는 기본 스레드에서 변수의 값으로 초기화할 변수입니다.
설명
copyin
는 다음 지시문에 적용됩니다.
자세한 내용은 2.7.2.7 복사를 참조 하세요.
예시
사용 copyin
예제는 threadprivate를 참조하세요.
copyprivate
하나 이상의 변수를 모든 스레드 간에 공유되도록 지정합니다.
copyprivate(var)
매개 변수
var
공유할 변수가 하나 이상 있습니다. 둘 이상의 변수를 지정하면 변수 이름을 쉼표로 구분합니다.
설명
copyprivate
는 단일 지시문에 적용됩니다.
자세한 내용은 2.7.2.8 copyprivate를 참조 하세요.
예시
// omp_copyprivate.cpp
// compile with: /openmp
#include <stdio.h>
#include <omp.h>
float x, y, fGlobal = 1.0;
#pragma omp threadprivate(x, y)
float get_float() {
fGlobal += 0.001;
return fGlobal;
}
void use_float(float f, int t) {
printf_s("Value = %f, thread = %d\n", f, t);
}
void CopyPrivate(float a, float b) {
#pragma omp single copyprivate(a, b, x, y)
{
a = get_float();
b = get_float();
x = get_float();
y = get_float();
}
use_float(a, omp_get_thread_num());
use_float(b, omp_get_thread_num());
use_float(x, omp_get_thread_num());
use_float(y, omp_get_thread_num());
}
int main() {
float a = 9.99, b = 123.456;
printf_s("call CopyPrivate from a single thread\n");
CopyPrivate(9.99, 123.456);
printf_s("call CopyPrivate from a parallel region\n");
#pragma omp parallel
{
CopyPrivate(a, b);
}
}
call CopyPrivate from a single thread
Value = 1.001000, thread = 0
Value = 1.002000, thread = 0
Value = 1.003000, thread = 0
Value = 1.004000, thread = 0
call CopyPrivate from a parallel region
Value = 1.005000, thread = 0
Value = 1.005000, thread = 1
Value = 1.006000, thread = 0
Value = 1.006000, thread = 1
Value = 1.007000, thread = 0
Value = 1.007000, thread = 1
Value = 1.008000, thread = 0
Value = 1.008000, thread = 1
default
병렬 영역에서 범위가 지정되지 않은 변수의 동작을 지정합니다.
default(shared | none)
설명
shared
절이 지정되지 않은 경우 default
적용됩니다. 즉, 병렬 영역의 변수는 공유 절로 지정된 것처럼 처리됩니다. none
은 프라이빗, 공유, 축소, firstprivate 또는 lastprivate 절로 범위가 지정되지 않은 병렬 지역에 사용되는 변수가 컴파일러 오류를 발생시키는 것을 의미합니다.
default
는 다음 지시문에 적용됩니다.
자세한 내용은 2.7.2.5 기본값을 참조하세요.
예시
사용 default
예제는 private을 참조하세요.
firstprivate
각 스레드에 고유한 변수 인스턴스가 있어야 하며 변수가 병렬 구문 앞에 존재하기 때문에 변수 값을 사용하여 초기화되도록 지정합니다.
firstprivate(var)
매개 변수
var
각 스레드에 인스턴스가 있고 이 변수는 병렬 구문 앞에 존재하기 때문에 변수의 값으로 초기화됩니다. 둘 이상의 변수를 지정하면 변수 이름을 쉼표로 구분합니다.
설명
firstprivate
는 다음 지시문에 적용됩니다.
자세한 내용은 2.7.2.2 firstprivate를 참조 하세요.
예시
사용 firstprivate
예제는 private의 예제를 참조하세요.
if(OpenMP)
루프를 병렬 또는 직렬로 실행할지 여부를 지정합니다.
if(expression)
매개 변수
expression
true(0이 아닌)로 평가되면 병렬 영역의 코드가 병렬로 실행되는 정수 계열 식입니다. 식이 false(0)로 평가되면 병렬 영역이 단일 스레드에 의해 직렬로 실행됩니다.
설명
if
는 다음 지시문에 적용됩니다.
자세한 내용은 2.3 병렬 구문을 참조하세요.
예시
// omp_if.cpp
// compile with: /openmp
#include <stdio.h>
#include <omp.h>
void test(int val)
{
#pragma omp parallel if (val)
if (omp_in_parallel())
{
#pragma omp single
printf_s("val = %d, parallelized with %d threads\n",
val, omp_get_num_threads());
}
else
{
printf_s("val = %d, serialized\n", val);
}
}
int main( )
{
omp_set_num_threads(2);
test(0);
test(2);
}
val = 0, serialized
val = 2, parallelized with 2 threads
lastprivate
바깥쪽 컨텍스트의 변수 버전이 최종 반복(for-loop 구문) 또는 마지막 섹션(#pragma 섹션)을 실행하는 스레드의 프라이빗 버전과 동일하게 설정되도록 지정합니다.
lastprivate(var)
매개 변수
var
최종 반복(for-loop 구문) 또는 마지막 섹션(#pragma 섹션)을 실행하는 스레드의 프라이빗 버전과 동일하게 설정된 변수입니다.
설명
lastprivate
는 다음 지시문에 적용됩니다.
자세한 내용은 2.7.2.3 lastprivate를 참조 하세요.
예시
절 사용 lastprivate
예제는 일정을 참조하세요.
nowait
지시문에서 암시적 장벽을 재정의합니다.
nowait
설명
nowait
는 다음 지시문에 적용됩니다.
자세한 내용은 구문의 경우 2.4.1, 2.4.2 섹션 구문 및 2.4.3 단일 구문을 참조하세요.
예시
// omp_nowait.cpp
// compile with: /openmp /c
#include <stdio.h>
#define SIZE 5
void test(int *a, int *b, int *c, int size)
{
int i;
#pragma omp parallel
{
#pragma omp for nowait
for (i = 0; i < size; i++)
b[i] = a[i] * a[i];
#pragma omp for nowait
for (i = 0; i < size; i++)
c[i] = a[i]/2;
}
}
int main( )
{
int a[SIZE], b[SIZE], c[SIZE];
int i;
for (i=0; i<SIZE; i++)
a[i] = i;
test(a,b,c, SIZE);
for (i=0; i<SIZE; i++)
printf_s("%d, %d, %d\n", a[i], b[i], c[i]);
}
0, 0, 0
1, 1, 0
2, 4, 1
3, 9, 1
4, 16, 2
num_threads
스레드 팀의 스레드 수를 설정합니다.
num_threads(num)
매개 변수
num
스레드 수
설명
절에는 num_threads
omp_set_num_threads 함수와 동일한 기능이 있습니다.
num_threads
는 다음 지시문에 적용됩니다.
자세한 내용은 2.3 병렬 구문을 참조하세요.
예시
절 사용 num_threads
예제는 병렬을 참조하세요.
ordered
순서가 지정된 지시문을 루프에서 사용하는 경우 문에 대한 병렬에 필요합니다.
ordered
설명
ordered
는 for 지시문에 적용됩니다.
자세한 내용은 구문에 대한 2.4.1을 참조하세요.
예시
절 사용 ordered
예제는 ordered를 참조하세요.
private
각 스레드에 변수의 자체 인스턴스가 있어야 하며
private(var)
매개 변수
var
각 스레드에 인스턴스가 있는 변수입니다.
설명
private
는 다음 지시문에 적용됩니다.
자세한 내용은 2.7.2.1 private을 참조 하세요.
예시
// openmp_private.c
// compile with: /openmp
#include <windows.h>
#include <assert.h>
#include <stdio.h>
#include <omp.h>
#define NUM_THREADS 4
#define SLEEP_THREAD 1
#define NUM_LOOPS 2
enum Types {
ThreadPrivate,
Private,
FirstPrivate,
LastPrivate,
Shared,
MAX_TYPES
};
int nSave[NUM_THREADS][MAX_TYPES][NUM_LOOPS] = {{0}};
int nThreadPrivate;
#pragma omp threadprivate(nThreadPrivate)
#pragma warning(disable:4700)
int main() {
int nPrivate = NUM_THREADS;
int nFirstPrivate = NUM_THREADS;
int nLastPrivate = NUM_THREADS;
int nShared = NUM_THREADS;
int nRet = 0;
int i;
int j;
int nLoop = 0;
nThreadPrivate = NUM_THREADS;
printf_s("These are the variables before entry "
"into the parallel region.\n");
printf_s("nThreadPrivate = %d\n", nThreadPrivate);
printf_s(" nPrivate = %d\n", nPrivate);
printf_s(" nFirstPrivate = %d\n", nFirstPrivate);
printf_s(" nLastPrivate = %d\n", nLastPrivate);
printf_s(" nShared = %d\n\n", nShared);
omp_set_num_threads(NUM_THREADS);
#pragma omp parallel copyin(nThreadPrivate) private(nPrivate) shared(nShared) firstprivate(nFirstPrivate)
{
#pragma omp for schedule(static) lastprivate(nLastPrivate)
for (i = 0 ; i < NUM_THREADS ; ++i) {
for (j = 0 ; j < NUM_LOOPS ; ++j) {
int nThread = omp_get_thread_num();
assert(nThread < NUM_THREADS);
if (nThread == SLEEP_THREAD)
Sleep(100);
nSave[nThread][ThreadPrivate][j] = nThreadPrivate;
nSave[nThread][Private][j] = nPrivate;
nSave[nThread][Shared][j] = nShared;
nSave[nThread][FirstPrivate][j] = nFirstPrivate;
nSave[nThread][LastPrivate][j] = nLastPrivate;
nThreadPrivate = nThread;
nPrivate = nThread;
nShared = nThread;
nLastPrivate = nThread;
--nFirstPrivate;
}
}
}
for (i = 0 ; i < NUM_LOOPS ; ++i) {
for (j = 0 ; j < NUM_THREADS ; ++j) {
printf_s("These are the variables at entry of "
"loop %d of thread %d.\n", i + 1, j);
printf_s("nThreadPrivate = %d\n",
nSave[j][ThreadPrivate][i]);
printf_s(" nPrivate = %d\n",
nSave[j][Private][i]);
printf_s(" nFirstPrivate = %d\n",
nSave[j][FirstPrivate][i]);
printf_s(" nLastPrivate = %d\n",
nSave[j][LastPrivate][i]);
printf_s(" nShared = %d\n\n",
nSave[j][Shared][i]);
}
}
printf_s("These are the variables after exit from "
"the parallel region.\n");
printf_s("nThreadPrivate = %d (The last value in the "
"main thread)\n", nThreadPrivate);
printf_s(" nPrivate = %d (The value prior to "
"entering parallel region)\n", nPrivate);
printf_s(" nFirstPrivate = %d (The value prior to "
"entering parallel region)\n", nFirstPrivate);
printf_s(" nLastPrivate = %d (The value from the "
"last iteration of the loop)\n", nLastPrivate);
printf_s(" nShared = %d (The value assigned, "
"from the delayed thread, %d)\n\n",
nShared, SLEEP_THREAD);
}
These are the variables before entry into the parallel region.
nThreadPrivate = 4
nPrivate = 4
nFirstPrivate = 4
nLastPrivate = 4
nShared = 4
These are the variables at entry of loop 1 of thread 0.
nThreadPrivate = 4
nPrivate = 1310720
nFirstPrivate = 4
nLastPrivate = 1245104
nShared = 3
These are the variables at entry of loop 1 of thread 1.
nThreadPrivate = 4
nPrivate = 4488
nFirstPrivate = 4
nLastPrivate = 19748
nShared = 0
These are the variables at entry of loop 1 of thread 2.
nThreadPrivate = 4
nPrivate = -132514848
nFirstPrivate = 4
nLastPrivate = -513199792
nShared = 4
These are the variables at entry of loop 1 of thread 3.
nThreadPrivate = 4
nPrivate = 1206
nFirstPrivate = 4
nLastPrivate = 1204
nShared = 2
These are the variables at entry of loop 2 of thread 0.
nThreadPrivate = 0
nPrivate = 0
nFirstPrivate = 3
nLastPrivate = 0
nShared = 0
These are the variables at entry of loop 2 of thread 1.
nThreadPrivate = 1
nPrivate = 1
nFirstPrivate = 3
nLastPrivate = 1
nShared = 1
These are the variables at entry of loop 2 of thread 2.
nThreadPrivate = 2
nPrivate = 2
nFirstPrivate = 3
nLastPrivate = 2
nShared = 2
These are the variables at entry of loop 2 of thread 3.
nThreadPrivate = 3
nPrivate = 3
nFirstPrivate = 3
nLastPrivate = 3
nShared = 3
These are the variables after exit from the parallel region.
nThreadPrivate = 0 (The last value in the main thread)
nPrivate = 4 (The value prior to entering parallel region)
nFirstPrivate = 4 (The value prior to entering parallel region)
nLastPrivate = 3 (The value from the last iteration of the loop)
nShared = 1 (The value assigned, from the delayed thread, 1)
reduction
각 스레드에 대해 비공개인 하나 이상의 변수가 병렬 영역의 끝에 있는 감소 작업의 대상이 되도록 지정합니다.
reduction(operation:var)
매개 변수
작업
병렬 영역의 끝에 있는 변수 var 에서 수행할 작업에 대한 연산자입니다.
var
스칼라 감소를 수행할 하나 이상의 변수입니다. 둘 이상의 변수를 지정하면 변수 이름을 쉼표로 구분합니다.
설명
reduction
는 다음 지시문에 적용됩니다.
자세한 내용은 2.7.2.6 감소를 참조하세요.
예시
// omp_reduction.cpp
// compile with: /openmp
#include <stdio.h>
#include <omp.h>
#define NUM_THREADS 4
#define SUM_START 1
#define SUM_END 10
#define FUNC_RETS {1, 1, 1, 1, 1}
int bRets[5] = FUNC_RETS;
int nSumCalc = ((SUM_START + SUM_END) * (SUM_END - SUM_START + 1)) / 2;
int func1( ) {return bRets[0];}
int func2( ) {return bRets[1];}
int func3( ) {return bRets[2];}
int func4( ) {return bRets[3];}
int func5( ) {return bRets[4];}
int main( )
{
int nRet = 0,
nCount = 0,
nSum = 0,
i,
bSucceed = 1;
omp_set_num_threads(NUM_THREADS);
#pragma omp parallel reduction(+ : nCount)
{
nCount += 1;
#pragma omp for reduction(+ : nSum)
for (i = SUM_START ; i <= SUM_END ; ++i)
nSum += i;
#pragma omp sections reduction(&& : bSucceed)
{
#pragma omp section
{
bSucceed = bSucceed && func1( );
}
#pragma omp section
{
bSucceed = bSucceed && func2( );
}
#pragma omp section
{
bSucceed = bSucceed && func3( );
}
#pragma omp section
{
bSucceed = bSucceed && func4( );
}
#pragma omp section
{
bSucceed = bSucceed && func5( );
}
}
}
printf_s("The parallel section was executed %d times "
"in parallel.\n", nCount);
printf_s("The sum of the consecutive integers from "
"%d to %d, is %d\n", 1, 10, nSum);
if (bSucceed)
printf_s("All of the functions, func1 through "
"func5 succeeded!\n");
else
printf_s("One or more of the functions, func1 "
"through func5 failed!\n");
if (nCount != NUM_THREADS)
{
printf_s("ERROR: For %d threads, %d were counted!\n",
NUM_THREADS, nCount);
nRet |= 0x1;
}
if (nSum != nSumCalc)
{
printf_s("ERROR: The sum of %d through %d should be %d, "
"but %d was reported!\n",
SUM_START, SUM_END, nSumCalc, nSum);
nRet |= 0x10;
}
if (bSucceed != (bRets[0] && bRets[1] &&
bRets[2] && bRets[3] && bRets[4]))
{
printf_s("ERROR: The sum of %d through %d should be %d, "
"but %d was reported!\n",
SUM_START, SUM_END, nSumCalc, nSum);
nRet |= 0x100;
}
}
The parallel section was executed 4 times in parallel.
The sum of the consecutive integers from 1 to 10, is 55
All of the functions, func1 through func5 succeeded!
schedule
for 지시문에 적용됩니다.
schedule(type[,size])
매개 변수
type
일정의 종류(예dynamic
: , guided
또는 runtime
static
.)
size
(선택 사항) 반복의 크기를 지정합니다. 크기 는 정수여야 합니다. 형식이 runtime
.인 경우 유효하지 않습니다.
설명
자세한 내용은 구문에 대한 2.4.1을 참조하세요.
예시
// omp_schedule.cpp
// compile with: /openmp
#include <windows.h>
#include <stdio.h>
#include <omp.h>
#define NUM_THREADS 4
#define STATIC_CHUNK 5
#define DYNAMIC_CHUNK 5
#define NUM_LOOPS 20
#define SLEEP_EVERY_N 3
int main( )
{
int nStatic1[NUM_LOOPS],
nStaticN[NUM_LOOPS];
int nDynamic1[NUM_LOOPS],
nDynamicN[NUM_LOOPS];
int nGuided[NUM_LOOPS];
omp_set_num_threads(NUM_THREADS);
#pragma omp parallel
{
#pragma omp for schedule(static, 1)
for (int i = 0 ; i < NUM_LOOPS ; ++i)
{
if ((i % SLEEP_EVERY_N) == 0)
Sleep(0);
nStatic1[i] = omp_get_thread_num( );
}
#pragma omp for schedule(static, STATIC_CHUNK)
for (int i = 0 ; i < NUM_LOOPS ; ++i)
{
if ((i % SLEEP_EVERY_N) == 0)
Sleep(0);
nStaticN[i] = omp_get_thread_num( );
}
#pragma omp for schedule(dynamic, 1)
for (int i = 0 ; i < NUM_LOOPS ; ++i)
{
if ((i % SLEEP_EVERY_N) == 0)
Sleep(0);
nDynamic1[i] = omp_get_thread_num( );
}
#pragma omp for schedule(dynamic, DYNAMIC_CHUNK)
for (int i = 0 ; i < NUM_LOOPS ; ++i)
{
if ((i % SLEEP_EVERY_N) == 0)
Sleep(0);
nDynamicN[i] = omp_get_thread_num( );
}
#pragma omp for schedule(guided)
for (int i = 0 ; i < NUM_LOOPS ; ++i)
{
if ((i % SLEEP_EVERY_N) == 0)
Sleep(0);
nGuided[i] = omp_get_thread_num( );
}
}
printf_s("------------------------------------------------\n");
printf_s("| static | static | dynamic | dynamic | guided |\n");
printf_s("| 1 | %d | 1 | %d | |\n",
STATIC_CHUNK, DYNAMIC_CHUNK);
printf_s("------------------------------------------------\n");
for (int i=0; i<NUM_LOOPS; ++i)
{
printf_s("| %d | %d | %d | %d |"
" %d |\n",
nStatic1[i], nStaticN[i],
nDynamic1[i], nDynamicN[i], nGuided[i]);
}
printf_s("------------------------------------------------\n");
}
------------------------------------------------
| static | static | dynamic | dynamic | guided |
| 1 | 5 | 1 | 5 | |
------------------------------------------------
| 0 | 0 | 0 | 2 | 1 |
| 1 | 0 | 3 | 2 | 1 |
| 2 | 0 | 3 | 2 | 1 |
| 3 | 0 | 3 | 2 | 1 |
| 0 | 0 | 2 | 2 | 1 |
| 1 | 1 | 2 | 3 | 3 |
| 2 | 1 | 2 | 3 | 3 |
| 3 | 1 | 0 | 3 | 3 |
| 0 | 1 | 0 | 3 | 3 |
| 1 | 1 | 0 | 3 | 2 |
| 2 | 2 | 1 | 0 | 2 |
| 3 | 2 | 1 | 0 | 2 |
| 0 | 2 | 1 | 0 | 3 |
| 1 | 2 | 2 | 0 | 3 |
| 2 | 2 | 2 | 0 | 0 |
| 3 | 3 | 2 | 1 | 0 |
| 0 | 3 | 3 | 1 | 1 |
| 1 | 3 | 3 | 1 | 1 |
| 2 | 3 | 3 | 1 | 1 |
| 3 | 3 | 0 | 1 | 3 |
------------------------------------------------
공유
하나 이상의 변수를 모든 스레드 간에 공유되도록 지정합니다.
shared(var)
매개 변수
var
공유할 변수가 하나 이상 있습니다. 둘 이상의 변수를 지정하면 변수 이름을 쉼표로 구분합니다.
설명
스레드 간에 변수를 공유하는 또 다른 방법은 copyprivate 절을 사용하는 것입니다 .
shared
는 다음 지시문에 적용됩니다.
자세한 내용은 2.7.2.4 공유를 참조하세요.
예시
사용 shared
예제는 private을 참조하세요.