OpenMP – klauzule
Poskytuje odkazy na klauzule používané v rozhraní OpenMP API.
Visual C++ podporuje následující klauzule OpenMP.
Obecné atributy:
Klauzule | Popis |
---|---|
když | Určuje, zda má být smyčka spuštěna paralelně nebo sériově. |
num_threads | Nastaví počet vláken v týmu vláken. |
objednaný | Vyžaduje se paralelně pro příkaz, pokud se má ve smyčce použít uspořádaná direktiva. |
schedule | Platí pro směrnici for . |
nowait | Přepíše bariéru implicitní v direktivě. |
Atributy sdílení dat:
Klauzule | Popis |
---|---|
private | Určuje, že každé vlákno by mělo mít vlastní instanci proměnné. |
firstprivate | Určuje, že každé vlákno by mělo mít vlastní instanci proměnné a že proměnná by měla být inicializována s hodnotou proměnné, protože existuje před paralelním konstruktorem. |
lastprivate | Určuje, že verze nadřazeného kontextu proměnné je nastavená na privátní verzi vlákna, která spouští konečnou iteraci (konstruktor for-loop) nebo poslední oddíl (#pragma oddíly). |
společný | Určuje, že jedna nebo více proměnných by se měla sdílet mezi všemi vlákny. |
default | Určuje chování neskopovaných proměnných v paralelní oblasti. |
reduction | Určuje, že jedna nebo více proměnných, které jsou soukromé pro každé vlákno, jsou předmětem operace redukce na konci paralelní oblasti. |
copyin | Umožňuje vlákenm přístup k hodnotě hlavního vlákna pro proměnnou threadprivate . |
copyprivate | Určuje, že jedna nebo více proměnných by se měla sdílet mezi všemi vlákny. |
copyin
Umožňuje vlákenm přístup k hodnotě hlavního vlákna pro proměnnou threadprivate .
copyin(var)
Parametry
var
Proměnná threadprivate
, která bude inicializována hodnotou proměnné v hlavním vlákně, protože existuje před paralelním konstruktorem.
Poznámky
copyin
se vztahuje na následující direktivy:
Další informace naleznete v části 2.7.2.7 copyin.
Příklad
Příklad použití copyin
najdete v tématu threadprivate .
copyprivate
Určuje, že jedna nebo více proměnných by se měla sdílet mezi všemi vlákny.
copyprivate(var)
Parametry
var
Jednu nebo více proměnných, které chcete sdílet. Pokud je zadáno více než jedna proměnná, oddělte názvy proměnných čárkou.
Poznámky
copyprivate
se vztahuje na jedinou směrnici.
Další informace najdete v tématu 2.7.2.8 copyprivate.
Příklad
// 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
Určuje chování neskopovaných proměnných v paralelní oblasti.
default(shared | none)
Poznámky
shared
, která je platná, pokud default
je klauzule nezadaná, znamená, že jakákoli proměnná v paralelní oblasti bude považována za zadanou se sdílenou klauzulí. none
znamená, že všechny proměnné použité v paralelní oblasti, které nejsou vymezeny oborem privátní, sdílené, redukce, firstprivate nebo lastprivate klauzule, způsobí chybu kompilátoru.
default
se vztahuje na následující direktivy:
Další informace najdete ve výchozím nastavení 2.7.2.5.
Příklad
Podívejte se na soukromou ukázku použití default
.
firstprivate
Určuje, že každé vlákno by mělo mít vlastní instanci proměnné a že proměnná by měla být inicializována s hodnotou proměnné, protože existuje před paralelním konstruktorem.
firstprivate(var)
Parametry
var
Proměnná, která má mít instance v každém vlákně a která se inicializuje s hodnotou proměnné, protože existuje před paralelním konstruktorem. Pokud je zadáno více než jedna proměnná, oddělte názvy proměnných čárkou.
Poznámky
firstprivate
se vztahuje na následující direktivy:
Další informace naleznete v tématu 2.7.2.2 firstprivate.
Příklad
Příklad použití firstprivate
najdete v příkladu v privátním souboru.
if (OpenMP)
Určuje, zda má být smyčka spuštěna paralelně nebo sériově.
if(expression)
Parametry
výraz
Integrální výraz, který je vyhodnocen jako true (nenulový), způsobí paralelní spuštění kódu v paralelní oblasti. Pokud se výraz vyhodnotí jako false (nula), provede se paralelní oblast sériově (jedním vláknem).
Poznámky
if
se vztahuje na následující direktivy:
Další informace naleznete v části 2.3 paralelní konstrukce.
Příklad
// 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
Určuje, že verze nadřazeného kontextu proměnné je nastavená na privátní verzi vlákna, která spouští konečnou iteraci (konstruktor for-loop) nebo poslední oddíl (#pragma oddíly).
lastprivate(var)
Parametry
var
Proměnná, která je nastavená na privátní verzi vlákna, spustí konečnou iteraci (konstruktor for-loop) nebo poslední oddíl (#pragma oddíly).
Poznámky
lastprivate
se vztahuje na následující direktivy:
Další informace najdete v tématu 2.7.2.3 lastprivate.
Příklad
Podívejte se na plán příkladu klauzule using lastprivate
.
nowait
Přepíše bariéru implicitní v direktivě.
nowait
Poznámky
nowait
se vztahuje na následující direktivy:
Další informace naleznete v tématu 2.4.1 pro konstruktor, 2.4.2 oddíly konstrukce a 2.4.3 jeden konstruktor.
Příklad
// 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
Nastaví počet vláken v týmu vláken.
num_threads(num)
Parametry
Num
Počet vláken
Poznámky
Klauzule num_threads
má stejné funkce jako funkce omp_set_num_threads .
num_threads
se vztahuje na následující direktivy:
Další informace naleznete v části 2.3 paralelní konstrukce.
Příklad
Příklad klauzule using num_threads
najdete paralelně.
ordered
Vyžaduje se paralelně pro příkaz, pokud se má ve smyčce použít uspořádaná direktiva.
ordered
Poznámky
ordered
se vztahuje na směrnici pro účely .
Další informace naleznete v tématu 2.4.1 pro konstruktor.
Příklad
Podívejte se na seřazený příklad klauzule using ordered
.
private
Určuje, že každé vlákno by mělo mít vlastní instanci proměnné.
private(var)
Parametry
var
Proměnná, která má mít instance v každém vlákně.
Poznámky
private
se vztahuje na následující direktivy:
Další informace naleznete v části 2.7.2.1 private.
Příklad
// 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
Určuje, že jedna nebo více proměnných, které jsou soukromé pro každé vlákno, jsou předmětem operace redukce na konci paralelní oblasti.
reduction(operation:var)
Parametry
operace
Operátor operace, který má provádět s proměnnými var na konci paralelní oblasti.
var
Jedna nebo více proměnných, u kterých se má provést skalární redukce. Pokud je zadáno více než jedna proměnná, oddělte názvy proměnných čárkou.
Poznámky
reduction
se vztahuje na následující direktivy:
Další informace naleznete ve verzi 2.7.2.6.
Příklad
// 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!
plán
Platí pro směrnici for .
schedule(type[,size])
Parametry
type
Druh plánování, buď dynamic
, guided
, runtime
nebo static
.
velikost
(Volitelné) Určuje velikost iterací. velikost musí být celé číslo. Není platný, pokud je runtime
typ .
Poznámky
Další informace naleznete v tématu 2.4.1 pro konstruktor.
Příklad
// 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
Určuje, že jedna nebo více proměnných by se měla sdílet mezi všemi vlákny.
shared(var)
Parametry
var
Jednu nebo více proměnných, které chcete sdílet. Pokud je zadáno více než jedna proměnná, oddělte názvy proměnných čárkou.
Poznámky
Dalším způsobem sdílení proměnných mezi vlákny je klauzule copyprivate .
shared
se vztahuje na následující direktivy:
Další informace najdete ve sdílené verzi 2.7.2.4.
Příklad
Podívejte se na soukromou ukázku použití shared
.