Direktivy jazyka OpenMP
Poskytuje odkazy na direktivy používané v rozhraní OpenMP API.
Visual C++ podporuje následující direktivy OpenMP.
Pro paralelní sdílení práce:
Direktiva | Popis |
---|---|
parallel | Definuje paralelní oblast, což je kód, který bude spuštěný několika vlákny paralelně. |
for | Způsobí rozdělení práce ve for smyčce uvnitř paralelní oblasti mezi vlákna. |
sekce | Identifikuje oddíly kódu, které se mají rozdělit mezi všechna vlákna. |
single | Umožňuje určit, že část kódu by měla být spuštěna v jednom vlákně, ne nutně hlavní vlákno. |
Pro hlavní vlákno a synchronizaci:
Direktiva | Popis |
---|---|
master | Určuje, že část programu by měla spouštět pouze hlavní vlákno. |
critical | Určuje, že se kód spouští pouze na jednom vlákně najednou. |
barrier | Synchronizuje všechna vlákna v týmu; všechna vlákna se pozastaví na bariérě, dokud všechna vlákna nespustí bariéru. |
atomic | Určuje, že umístění paměti, které se bude aktualizovat atomicky. |
spláchnout | Určuje, že všechna vlákna mají stejné zobrazení paměti pro všechny sdílené objekty. |
objednaný | Určuje, že kód pod paralelizovanou for smyčkou by se měl spustit jako sekvenční smyčka. |
Pro datové prostředí:
Direktiva | Popis |
---|---|
threadprivate | Určuje, že proměnná je pro vlákno soukromá. |
atomic
Určuje, že umístění paměti, které se bude aktualizovat atomicky.
#pragma omp atomic
expression
Parametry
výraz
Příkaz, který má lvalue, jehož umístění paměti chcete chránit před více než jedním zápisem.
Poznámky
Direktiva atomic
nepodporuje žádné klauzule.
Další informace naleznete v článku 2.6.4 atomic konstruktor.
Příklad
// omp_atomic.cpp
// compile with: /openmp
#include <stdio.h>
#include <omp.h>
#define MAX 10
int main() {
int count = 0;
#pragma omp parallel num_threads(MAX)
{
#pragma omp atomic
count++;
}
printf_s("Number of threads: %d\n", count);
}
Number of threads: 10
barrier
Synchronizuje všechna vlákna v týmu; všechna vlákna se pozastaví na bariérě, dokud všechna vlákna nespustí bariéru.
#pragma omp barrier
Poznámky
Direktiva barrier
nepodporuje žádné klauzule.
Další informace naleznete v tématu 2.6.3 bariérová direktiva.
Příklad
Ukázku použití barrier
najdete v hlavní části.
critical
Určuje, že se kód spouští pouze na jednom vlákně najednou.
#pragma omp critical [(name)]
{
code_block
}
Parametry
Jméno
(Volitelné) Název pro identifikaci kritického kódu. Název musí být uzavřený v závorkách.
Poznámky
Direktiva critical
nepodporuje žádné klauzule.
Další informace naleznete v tématu 2.6.2 kritický konstruktor.
Příklad
// omp_critical.cpp
// compile with: /openmp
#include <omp.h>
#include <stdio.h>
#include <stdlib.h>
#define SIZE 10
int main()
{
int i;
int max;
int a[SIZE];
for (i = 0; i < SIZE; i++)
{
a[i] = rand();
printf_s("%d\n", a[i]);
}
max = a[0];
#pragma omp parallel for num_threads(4)
for (i = 1; i < SIZE; i++)
{
if (a[i] > max)
{
#pragma omp critical
{
// compare a[i] and max again because max
// could have been changed by another thread after
// the comparison outside the critical section
if (a[i] > max)
max = a[i];
}
}
}
printf_s("max = %d\n", max);
}
41
18467
6334
26500
19169
15724
11478
29358
26962
24464
max = 29358
flush
Určuje, že všechna vlákna mají stejné zobrazení paměti pro všechny sdílené objekty.
#pragma omp flush [(var)]
Parametry
var
(Volitelné) Seznam proměnných oddělených čárkami, které představují objekty, které chcete synchronizovat. Pokud není zadána hodnota var , vyprázdní se veškerá paměť.
Poznámky
Direktiva flush
nepodporuje žádné klauzule.
Další informace naleznete v tématu 2.6.5 flush direktiva.
Příklad
// omp_flush.cpp
// compile with: /openmp
#include <stdio.h>
#include <omp.h>
void read(int *data) {
printf_s("read data\n");
*data = 1;
}
void process(int *data) {
printf_s("process data\n");
(*data)++;
}
int main() {
int data;
int flag;
flag = 0;
#pragma omp parallel sections num_threads(2)
{
#pragma omp section
{
printf_s("Thread %d: ", omp_get_thread_num( ));
read(&data);
#pragma omp flush(data)
flag = 1;
#pragma omp flush(flag)
// Do more work.
}
#pragma omp section
{
while (!flag) {
#pragma omp flush(flag)
}
#pragma omp flush(data)
printf_s("Thread %d: ", omp_get_thread_num( ));
process(&data);
printf_s("data = %d\n", data);
}
}
}
Thread 0: read data
Thread 1: process data
data = 2
pro
Způsobí rozdělení práce ve for
smyčce uvnitř paralelní oblasti mezi vlákna.
#pragma omp [parallel] for [clauses]
for_statement
Parametry
klauzule
(Volitelné) Nulové nebo více klauzulí najdete v části Poznámky .
for_statement
Smyčka for
. Nedefinované chování způsobí, že kód uživatele ve for
smyčce změní proměnnou indexu.
Poznámky
Direktiva for
podporuje následující klauzule:
Je-li parallel
rovněž zadán, clauses
může být libovolná klauzule přijatá parallel
direktivou nebo for
direktivou s výjimkou nowait
.
Další informace naleznete v tématu 2.4.1 pro konstruktor.
Příklad
// omp_for.cpp
// compile with: /openmp
#include <stdio.h>
#include <math.h>
#include <omp.h>
#define NUM_THREADS 4
#define NUM_START 1
#define NUM_END 10
int main() {
int i, nRet = 0, nSum = 0, nStart = NUM_START, nEnd = NUM_END;
int nThreads = 0, nTmp = nStart + nEnd;
unsigned uTmp = (unsigned((abs(nStart - nEnd) + 1)) *
unsigned(abs(nTmp))) / 2;
int nSumCalc = uTmp;
if (nTmp < 0)
nSumCalc = -nSumCalc;
omp_set_num_threads(NUM_THREADS);
#pragma omp parallel default(none) private(i) shared(nSum, nThreads, nStart, nEnd)
{
#pragma omp master
nThreads = omp_get_num_threads();
#pragma omp for
for (i=nStart; i<=nEnd; ++i) {
#pragma omp atomic
nSum += i;
}
}
if (nThreads == NUM_THREADS) {
printf_s("%d OpenMP threads were used.\n", NUM_THREADS);
nRet = 0;
}
else {
printf_s("Expected %d OpenMP threads, but %d were used.\n",
NUM_THREADS, nThreads);
nRet = 1;
}
if (nSum != nSumCalc) {
printf_s("The sum of %d through %d should be %d, "
"but %d was reported!\n",
NUM_START, NUM_END, nSumCalc, nSum);
nRet = 1;
}
else
printf_s("The sum of %d through %d is %d\n",
NUM_START, NUM_END, nSum);
}
4 OpenMP threads were used.
The sum of 1 through 10 is 55
master
Určuje, že část programu by měla spouštět pouze hlavní vlákno.
#pragma omp master
{
code_block
}
Poznámky
Direktiva master
nepodporuje žádné klauzule.
Další informace naleznete v tématu 2.6.1 hlavní konstruktor.
Chcete-li určit, že část kódu by měla být provedena v jednom vlákně, ne nutně hlavní vlákno, použijte místo toho jedinou direktivu.
Příklad
// compile with: /openmp
#include <omp.h>
#include <stdio.h>
int main( )
{
int a[5], i;
#pragma omp parallel
{
// Perform some computation.
#pragma omp for
for (i = 0; i < 5; i++)
a[i] = i * i;
// Print intermediate results.
#pragma omp master
for (i = 0; i < 5; i++)
printf_s("a[%d] = %d\n", i, a[i]);
// Wait.
#pragma omp barrier
// Continue with the computation.
#pragma omp for
for (i = 0; i < 5; i++)
a[i] += i;
}
}
a[0] = 0
a[1] = 1
a[2] = 4
a[3] = 9
a[4] = 16
ordered
Určuje, že kód pod paralelizovanou for
smyčkou by se měl spustit jako sekvenční smyčka.
#pragma omp ordered
structured-block
Poznámky
Direktiva ordered
musí být v dynamickém rozsahu objektu for nebo parallel for
konstruktoru s klauzulí ordered
.
Direktiva ordered
nepodporuje žádné klauzule.
Další informace naleznete v tématu 2.6.6 uspořádaný konstruktor.
Příklad
// omp_ordered.cpp
// compile with: /openmp
#include <stdio.h>
#include <omp.h>
static float a[1000], b[1000], c[1000];
void test(int first, int last)
{
#pragma omp for schedule(static) ordered
for (int i = first; i <= last; ++i) {
// Do something here.
if (i % 2)
{
#pragma omp ordered
printf_s("test() iteration %d\n", i);
}
}
}
void test2(int iter)
{
#pragma omp ordered
printf_s("test2() iteration %d\n", iter);
}
int main( )
{
int i;
#pragma omp parallel
{
test(1, 8);
#pragma omp for ordered
for (i = 0 ; i < 5 ; i++)
test2(i);
}
}
test() iteration 1
test() iteration 3
test() iteration 5
test() iteration 7
test2() iteration 0
test2() iteration 1
test2() iteration 2
test2() iteration 3
test2() iteration 4
parallel
Definuje paralelní oblast, což je kód, který bude spuštěný několika vlákny paralelně.
#pragma omp parallel [clauses]
{
code_block
}
Parametry
klauzule
(Volitelné) Nulové nebo více klauzulí najdete v části Poznámky .
Poznámky
Direktiva parallel
podporuje následující klauzule:
parallel
lze také použít s direktivami for a sections .
Další informace naleznete v části 2.3 paralelní konstrukce.
Příklad
Následující ukázka ukazuje, jak nastavit počet vláken a definovat paralelní oblast. Počet vláken se ve výchozím nastavení rovná počtu logických procesorů v počítači. Pokud máte například počítač s jedním fyzickým procesorem, který má povolenou hyperthreading, bude mít dva logické procesory a dvě vlákna. Pořadí výstupu se může lišit na různých počítačích.
// omp_parallel.cpp
// compile with: /openmp
#include <stdio.h>
#include <omp.h>
int main() {
#pragma omp parallel num_threads(4)
{
int i = omp_get_thread_num();
printf_s("Hello from thread %d\n", i);
}
}
Hello from thread 0
Hello from thread 1
Hello from thread 2
Hello from thread 3
sections
Identifikuje oddíly kódu, které se mají rozdělit mezi všechna vlákna.
#pragma omp [parallel] sections [clauses]
{
#pragma omp section
{
code_block
}
}
Parametry
klauzule
(Volitelné) Nulové nebo více klauzulí najdete v části Poznámky .
Poznámky
Direktiva sections
může obsahovat nulové nebo více section
direktiv.
Direktiva sections
podporuje následující klauzule:
Je-li parallel
rovněž zadán, clauses
může být libovolná klauzule přijatá parallel
direktivou nebo sections
direktivou s výjimkou nowait
.
Další informace naleznete v části 2.4.2 oddíly konstrukce.
Příklad
// omp_sections.cpp
// compile with: /openmp
#include <stdio.h>
#include <omp.h>
int main() {
#pragma omp parallel sections num_threads(4)
{
printf_s("Hello from thread %d\n", omp_get_thread_num());
#pragma omp section
printf_s("Hello from thread %d\n", omp_get_thread_num());
}
}
Hello from thread 0
Hello from thread 0
single
Umožňuje určit, že část kódu by měla být spuštěna v jednom vlákně, ne nutně hlavní vlákno.
#pragma omp single [clauses]
{
code_block
}
Parametry
klauzule
(Volitelné) Nulové nebo více klauzulí najdete v části Poznámky .
Poznámky
Direktiva single
podporuje následující klauzule:
Další informace naleznete v tématu 2.4.3 jeden konstruktor.
Chcete-li určit, že část kódu by měla být provedena pouze v hlavním vlákně, použijte místo toho hlavní direktivu.
Příklad
// omp_single.cpp
// compile with: /openmp
#include <stdio.h>
#include <omp.h>
int main() {
#pragma omp parallel num_threads(2)
{
#pragma omp single
// Only a single thread can read the input.
printf_s("read input\n");
// Multiple threads in the team compute the results.
printf_s("compute results\n");
#pragma omp single
// Only a single thread can write the output.
printf_s("write output\n");
}
}
read input
compute results
compute results
write output
threadprivate
Určuje, že proměnná je pro vlákno soukromá.
#pragma omp threadprivate(var)
Parametry
var
Seznam proměnných oddělených čárkami, které chcete v vlákně nastavit jako soukromé. var musí být buď globální proměnná nebo proměnná s oborem názvů, nebo místní statická proměnná.
Poznámky
Direktiva threadprivate
nepodporuje žádné klauzule.
Direktiva threadprivate
je založena na atributu vlákna pomocí klíčového slova __declspec ; omezení platí pro __declspec(thread)
threadprivate
. Proměnná threadprivate
například bude existovat v libovolném vlákně, které se spustilo v procesu, a ne pouze ve vláknech, která jsou součástí týmu vlákna, který vytvořila paralelní oblast. Mějte na paměti podrobnosti o této implementaci; Můžete si všimnout, že konstruktory pro threadprivate
uživatelem definovaný typ se volají častěji, než se očekává.
Můžete použít threadprivate
v knihovně DLL, která je staticky načtena při spuštění procesu, ale nelze použít threadprivate
v žádné knihovně DLL, která bude načtena prostřednictvím LoadLibrary , jako jsou knihovny DLL načtené s /DELAYLOAD (odložený import načítání), které také používá LoadLibrary
.
Proměnná threadprivate
destrukovatelného typu není zaručená, že má její destruktor volaný. Příklad:
struct MyType
{
~MyType();
};
MyType threaded_var;
#pragma omp threadprivate(threaded_var)
int main()
{
#pragma omp parallel
{}
}
Uživatelé nemají žádnou kontrolu nad tím, kdy se vlákna tvořící paralelní oblast ukončí. Pokud tato vlákna existují při ukončení procesu, vlákna nebudou upozorněna na ukončení procesu a destruktor nebude volán v threaded_var
žádném vlákně s výjimkou vlákna, která se ukončí (tady primární vlákno). Kód by tedy neměl počítat se správným zničením proměnných threadprivate
.
Další informace naleznete v tématu 2.7.1 threadprivate direktiva.
Příklad
Ukázku použití threadprivate
najdete v části Soukromé.