Klauzule OpenMP
Udostępnia linki do klauzul używanych w interfejsie API openMP.
Język Visual C++ obsługuje następujące klauzule OpenMP.
W przypadku atrybutów ogólnych:
Klauzula | opis |
---|---|
jeśli | Określa, czy pętla powinna być wykonywana równolegle, czy szeregowa. |
num_threads | Ustawia liczbę wątków w zespole wątków. |
Zamówione | Wymagana na równoległej instrukcji, jeśli w pętli ma być używana uporządkowana dyrektywa. |
schedule | Dotyczy dyrektywy for. |
nowait | Zastępuje barierę niejawną w dyrektywie. |
W przypadku atrybutów udostępniania danych:
Klauzula | opis |
---|---|
private | Określa, że każdy wątek powinien mieć własne wystąpienie zmiennej. |
firstprivate | Określa, że każdy wątek powinien mieć własne wystąpienie zmiennej i że zmienna powinna być inicjowana z wartością zmiennej, ponieważ istnieje przed konstrukcją równoległą. |
lastprivate | Określa, że wersja otaczającego kontekstu zmiennej jest ustawiona na wersję prywatną niezależnie od tego, który wątek wykonuje ostateczną iterację (konstrukcję dla pętli) lub ostatnią sekcję (#pragma sekcjach). |
Udostępnionych | Określa, że co najmniej jedna zmienna powinna być współdzielona między wszystkimi wątkami. |
default | Określa zachowanie zmiennych niezakresowych w regionie równoległym. |
reduction | Określa, że co najmniej jedna zmienna prywatna dla każdego wątku jest przedmiotem operacji redukcji na końcu regionu równoległego. |
copyin | Umożliwia wątkom dostęp do wartości wątku głównego dla zmiennej threadprivate . |
copyprivate | Określa, że co najmniej jedna zmienna powinna być współdzielona między wszystkimi wątkami. |
copyin
Umożliwia wątkom dostęp do wartości wątku głównego dla zmiennej threadprivate .
copyin(var)
Parametry
var
Zmienna threadprivate
, która zostanie zainicjowana z wartością zmiennej w głównym wątku, tak jak istnieje przed konstrukcją równoległą.
Uwagi
copyin
stosuje się do następujących dyrektyw:
Aby uzyskać więcej informacji, zobacz kopiowanie w wersji 2.7.2.7.
Przykład
Zobacz threadprivate , aby zapoznać się z przykładem użycia elementu copyin
.
copyprivate
Określa, że co najmniej jedna zmienna powinna być współdzielona między wszystkimi wątkami.
copyprivate(var)
Parametry
var
Co najmniej jedna zmienna do udostępnienia. Jeśli określono więcej niż jedną zmienną, należy oddzielić nazwy zmiennych przecinkami.
Uwagi
copyprivate
stosuje się do jednej dyrektywy.
Aby uzyskać więcej informacji, zobacz 2.7.2.8 copyprivate.
Przykład
// 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
domyślna
Określa zachowanie zmiennych niezakresowych w regionie równoległym.
default(shared | none)
Uwagi
shared
, który jest w mocy, jeśli klauzula default
jest nieokreślona, oznacza, że każda zmienna w regionie równoległym będzie traktowana tak, jakby została określona z klauzulą udostępnioną. none
Oznacza, że wszystkie zmienne używane w regionie równoległym, które nie są objęte zakresem prywatnym, udostępnionym, redukcji, firstprivate lub klauzuli lastprivate, spowodują błąd kompilatora.
default
stosuje się do następujących dyrektyw:
Aby uzyskać więcej informacji, zobacz domyślną 2.7.2.5.
Przykład
Zobacz prywatny , aby zapoznać się z przykładem użycia elementu default
.
firstprivate
Określa, że każdy wątek powinien mieć własne wystąpienie zmiennej i że zmienna powinna być inicjowana z wartością zmiennej, ponieważ istnieje przed konstrukcją równoległą.
firstprivate(var)
Parametry
var
Zmienna, która ma mieć wystąpienia w każdym wątku i które zostaną zainicjowane z wartością zmiennej, ponieważ istnieje przed konstrukcją równoległą. Jeśli określono więcej niż jedną zmienną, należy oddzielić nazwy zmiennych przecinkami.
Uwagi
firstprivate
stosuje się do następujących dyrektyw:
Aby uzyskać więcej informacji, zobacz 2.7.2.2 firstprivate.
Przykład
Przykład użycia elementu firstprivate
można znaleźć w przykładzie prywatnym.
if (OpenMP)
Określa, czy pętla powinna być wykonywana równolegle, czy szeregowa.
if(expression)
Parametry
wyrażenie
Wyrażenie całkowite, które, jeśli oblicza wartość true (nonzero), powoduje równoległe wykonanie kodu w regionie równoległym. Jeśli wyrażenie daje wartość false (zero), region równoległy jest wykonywany w trybie szeregowym (przez jeden wątek).
Uwagi
if
stosuje się do następujących dyrektyw:
Aby uzyskać więcej informacji, zobacz konstrukcja równoległa 2.3.
Przykład
// 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
Określa, że wersja otaczającego kontekstu zmiennej jest ustawiona na wersję prywatną niezależnie od tego, który wątek wykonuje ostateczną iterację (konstrukcję dla pętli) lub ostatnią sekcję (#pragma sekcjach).
lastprivate(var)
Parametry
var
Zmienna, która jest ustawiona na wersję prywatną każdego wątku, wykonuje ostateczną iterację (konstrukcję for-loop) lub ostatnią sekcję (#pragma sekcji).
Uwagi
lastprivate
stosuje się do następujących dyrektyw:
Aby uzyskać więcej informacji, zobacz 2.7.2.3 lastprivate.
Przykład
Zobacz harmonogram , aby zapoznać się z przykładem używania lastprivate
klauzuli .
nowait
Zastępuje barierę niejawną w dyrektywie.
nowait
Uwagi
nowait
stosuje się do następujących dyrektyw:
Aby uzyskać więcej informacji, zobacz konstrukcję konstrukcji 2.4.1, konstrukcję sekcji 2.4.2 i 2.4.3 pojedynczą konstrukcję.
Przykład
// 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
Ustawia liczbę wątków w zespole wątków.
num_threads(num)
Parametry
Num
Liczba wątków
Uwagi
Klauzula num_threads
ma taką samą funkcjonalność jak funkcja omp_set_num_threads .
num_threads
stosuje się do następujących dyrektyw:
Aby uzyskać więcej informacji, zobacz konstrukcja równoległa 2.3.
Przykład
Zobacz równoległe , aby zapoznać się z przykładem używania num_threads
klauzuli .
uporządkowany
Wymagana na równoległej instrukcji, jeśli w pętli ma być używana uporządkowana dyrektywa.
ordered
Uwagi
ordered
stosuje się do dyrektywy for .
Aby uzyskać więcej informacji, zobacz 2.4.1 dla konstrukcji.
Przykład
Zobacz uporządkowane , aby zapoznać się z przykładem używania ordered
klauzuli .
private
Określa, że każdy wątek powinien mieć własne wystąpienie zmiennej.
private(var)
Parametry
var
Zmienna, która ma mieć wystąpienia w każdym wątku.
Uwagi
private
stosuje się do następujących dyrektyw:
Aby uzyskać więcej informacji, zobacz prywatną 2.7.2.1.
Przykład
// 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
Określa, że co najmniej jedna zmienna prywatna dla każdego wątku jest przedmiotem operacji redukcji na końcu regionu równoległego.
reduction(operation:var)
Parametry
rozdzielnicy
Operator operacji do wykonania dla zmiennej var na końcu regionu równoległego.
var
Co najmniej jedna zmienna, na której ma być zmniejszana skalarna. Jeśli określono więcej niż jedną zmienną, należy oddzielić nazwy zmiennych przecinkami.
Uwagi
reduction
stosuje się do następujących dyrektyw:
Aby uzyskać więcej informacji, zobacz redukcja 2.7.2.6.
Przykład
// 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!
harmonogram
schedule(type[,size])
Parametry
type
Rodzaj planowania, dynamic
albo , guided
, runtime
lub static
.
rozmiar
(Opcjonalnie) Określa rozmiar iteracji. rozmiar musi być liczbą całkowitą. Nieprawidłowy, gdy typ to runtime
.
Uwagi
Aby uzyskać więcej informacji, zobacz 2.4.1 dla konstrukcji.
Przykład
// 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 |
------------------------------------------------
udostępnione
Określa, że co najmniej jedna zmienna powinna być współdzielona między wszystkimi wątkami.
shared(var)
Parametry
var
Co najmniej jedna zmienna do udostępnienia. Jeśli określono więcej niż jedną zmienną, należy oddzielić nazwy zmiennych przecinkami.
Uwagi
Innym sposobem udostępniania zmiennych między wątkami jest klauzula copyprivate .
shared
stosuje się do następujących dyrektyw:
Aby uzyskać więcej informacji, zobacz udostępnione 2.7.2.4.
Przykład
Zobacz prywatny , aby zapoznać się z przykładem użycia elementu shared
.