OpenMP-Direktiven
Stellt Links zu Direktiven bereit, die in der OpenMP-API verwendet werden.
Visual C++ unterstützt die folgenden OpenMP-Direktiven.
Für parallele Arbeitsfreigabe:
Anweisung | Beschreibung |
---|---|
parallel | Definiert einen parallelen Bereich, der Code ist, der von mehreren Threads parallel ausgeführt wird. |
for | Bewirkt, dass die Arbeit in einer for Schleife innerhalb eines parallelen Bereichs in Threads aufgeteilt wird. |
sections | Identifiziert Codeabschnitte, die in alle Threads unterteilt werden sollen. |
single | Hiermit können Sie angeben, dass ein Codeabschnitt in einem einzelnen Thread ausgeführt werden soll, nicht unbedingt der Hauptthread. |
Für Hauptthread und Synchronisierung:
Anweisung | Beschreibung |
---|---|
master | Gibt an, dass nur der Hauptthread einen Abschnitt des Programms ausführen soll. |
Kritisch | Gibt an, dass Code nur jeweils auf einem Thread ausgeführt wird. |
barrier | Synchronisiert alle Threads in einem Team; Alle Threads halten an der Barriere an, bis alle Threads die Barriere ausführen. |
atomic | Gibt an, dass ein Speicherspeicherort, der atomisch aktualisiert wird. |
flush | Gibt an, dass alle Threads dieselbe Ansicht des Arbeitsspeichers für alle freigegebenen Objekte aufweisen. |
angeordnet | Gibt an, dass Code unter einer parallelisierten for Schleife wie eine sequenzielle Schleife ausgeführt werden soll. |
Für Datenumgebung:
Anweisung | Beschreibung |
---|---|
threadprivate | Gibt an, dass eine Variable für einen Thread privat ist. |
atomic
Gibt an, dass ein Speicherspeicherort, der atomisch aktualisiert wird.
#pragma omp atomic
expression
Parameter
expression
Die Anweisung mit dem Wert "lvalue", deren Speicherspeicherort Sie vor mehreren Schreibvorgängen schützen möchten.
Hinweise
Die atomic
Direktive unterstützt keine Klauseln.
Weitere Informationen finden Sie unter 2.6.4 Atomkonstrukt.
Beispiel
// 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
Synchronisiert alle Threads in einem Team; Alle Threads halten an der Barriere an, bis alle Threads die Barriere ausführen.
#pragma omp barrier
Hinweise
Die barrier
Direktive unterstützt keine Klauseln.
Weitere Informationen finden Sie in der Barriererichtlinie 2.6.3.
Beispiel
Ein Beispiel für die Verwendung barrier
finden Sie unter Master.
Kritisch
Gibt an, dass Code nur auf einem Thread gleichzeitig ausgeführt wird.
#pragma omp critical [(name)]
{
code_block
}
Parameter
name
(Optional) Ein Name zum Identifizieren des kritischen Codes. Der Name muss in Klammern eingeschlossen werden.
Hinweise
Die critical
Direktive unterstützt keine Klauseln.
Weitere Informationen finden Sie im kritischen Konstrukt 2.6.2.
Beispiel
// 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
Gibt an, dass alle Threads dieselbe Ansicht des Arbeitsspeichers für alle freigegebenen Objekte aufweisen.
#pragma omp flush [(var)]
Parameter
var
(Optional) Eine durch Trennzeichen getrennte Liste von Variablen, die Objekte darstellen, die Sie synchronisieren möchten. Wenn "var " nicht angegeben ist, wird der gesamte Arbeitsspeicher geleert.
Hinweise
Die flush
Direktive unterstützt keine Klauseln.
Weitere Informationen finden Sie unter 2.6.5 Flush-Direktive.
Beispiel
// 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
für
Bewirkt, dass die Arbeit in einer for
Schleife innerhalb eines parallelen Bereichs in Threads aufgeteilt wird.
#pragma omp [parallel] for [clauses]
for_statement
Parameter
klauseln
(Optional) Null oder mehr Klauseln finden Sie im Abschnitt "Hinweise ".
for_statement
Eine for
Schleife. Das nicht definierte Verhalten führt dazu, dass der Benutzercode in der for
Schleife die Indexvariable ändert.
Hinweise
Die for
Direktive unterstützt die folgenden Klauseln:
Wenn parallel
auch angegeben, kann eine beliebige Klausel sein, clauses
die von den parallel
Richtlinien for
akzeptiert wird, außer nowait
.
Weitere Informationen finden Sie unter 2.4.1 für das Konstrukt.
Beispiel
// 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
Gibt an, dass nur der Hauptthread einen Abschnitt des Programms ausführen soll.
#pragma omp master
{
code_block
}
Hinweise
Die master
Direktive unterstützt keine Klauseln.
Weitere Informationen finden Sie unter 2.6.1 Master-Konstrukt.
Um anzugeben, dass ein Codeabschnitt in einem einzelnen Thread ausgeführt werden soll, verwenden Sie stattdessen die einzelne Direktive, nicht unbedingt den Hauptthread.
Beispiel
// 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
geordnete
Gibt an, dass Code unter einer parallelisierten for
Schleife wie eine sequenzielle Schleife ausgeführt werden soll.
#pragma omp ordered
structured-block
Hinweise
Die ordered
Richtlinie muss sich innerhalb des dynamischen Umfangs eines For- oder parallel for
Konstruierens mit einer ordered
Klausel belassen.
Die ordered
Direktive unterstützt keine Klauseln.
Weitere Informationen finden Sie unter 2.6.6 geordnetes Konstrukt.
Beispiel
// 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
Definiert einen parallelen Bereich, der Code ist, der von mehreren Threads parallel ausgeführt wird.
#pragma omp parallel [clauses]
{
code_block
}
Parameter
klauseln
(Optional) Null oder mehr Klauseln finden Sie im Abschnitt "Hinweise ".
Hinweise
Die parallel
Direktive unterstützt die folgenden Klauseln:
parallel
kann auch mit den Für - und Abschnittsdirektiven verwendet werden.
Weitere Informationen finden Sie unter 2.3 paralleles Konstrukt.
Beispiel
Das folgende Beispiel zeigt, wie Sie die Anzahl der Threads festlegen und einen parallelen Bereich definieren. Die Anzahl der Threads entspricht standardmäßig der Anzahl der logischen Prozessoren auf dem Computer. Wenn Sie z. B. einen Computer mit einem physischen Prozessor haben, der Hyperthreading aktiviert hat, verfügen sie über zwei logische Prozessoren und zwei Threads. Die Ausgabereihenfolge kann auf verschiedenen Computern variieren.
// 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
Identifiziert Codeabschnitte, die in alle Threads unterteilt werden sollen.
#pragma omp [parallel] sections [clauses]
{
#pragma omp section
{
code_block
}
}
Parameter
klauseln
(Optional) Null oder mehr Klauseln finden Sie im Abschnitt "Hinweise ".
Hinweise
Die sections
Direktive kann null oder mehr section
Direktiven enthalten.
Die sections
Direktive unterstützt die folgenden Klauseln:
Wenn parallel
auch angegeben, kann eine beliebige Klausel sein, clauses
die von den parallel
Richtlinien sections
akzeptiert wird, außer nowait
.
Weitere Informationen finden Sie im Abschnittskonstrukt 2.4.2.
Beispiel
// 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
Hiermit können Sie angeben, dass ein Codeabschnitt in einem einzelnen Thread ausgeführt werden soll, nicht unbedingt der Hauptthread.
#pragma omp single [clauses]
{
code_block
}
Parameter
klauseln
(Optional) Null oder mehr Klauseln finden Sie im Abschnitt "Hinweise ".
Hinweise
Die single
Direktive unterstützt die folgenden Klauseln:
Weitere Informationen finden Sie unter 2.4.3 single construct.
Um anzugeben, dass ein Codeabschnitt nur im Hauptthread ausgeführt werden soll, verwenden Sie stattdessen die Masterdirektive .
Beispiel
// 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
Gibt an, dass eine Variable für einen Thread privat ist.
#pragma omp threadprivate(var)
Parameter
var
Eine durch Trennzeichen getrennte Liste von Variablen, die Sie als privat für einen Thread festlegen möchten. var muss entweder eine globale oder namespacebezogene Variable oder eine lokale statische Variable sein.
Hinweise
Die threadprivate
Direktive unterstützt keine Klauseln.
Die threadprivate
Direktive basiert auf dem Thread-Attribut mit dem schlüsselwort __declspec ; limits on __declspec(thread)
apply to threadprivate
. Beispielsweise ist eine threadprivate
Variable in jedem Thread vorhanden, der im Prozess gestartet wurde, nicht nur in den Threads, die Teil eines Threadteams sind, der von einem parallelen Bereich bereitgestellt wird. Seien Sie sich dieser Implementierungsdetails bewusst; Möglicherweise stellen Sie fest, dass Konstruktoren für einen threadprivate
benutzerdefinierten Typ häufiger als erwartet bezeichnet werden.
Sie können in einer DLL verwenden threadprivate
, die beim Prozessstart statisch geladen wird. Sie können jedoch keine DLL verwenden threadprivate
, die über LoadLibrary geladen wird, z. B. DLLs, die mit /DELAYLOAD (Verzögerungsladeimport) geladen werden, die ebenfalls verwendet LoadLibrary
werden.
Eine threadprivate
Variable eines destruktierbaren Typs ist nicht garantiert, dass der Destruktor aufgerufen wird. Zum Beispiel:
struct MyType
{
~MyType();
};
MyType threaded_var;
#pragma omp threadprivate(threaded_var)
int main()
{
#pragma omp parallel
{}
}
Benutzer haben keine Kontrolle darüber, wann die Threads, die den parallelen Bereich bilden, beendet werden. Wenn diese Threads vorhanden sind, wenn der Prozess beendet wird, werden die Threads nicht über den Prozessende benachrichtigt, und der Destruktor wird für keinen Thread aufgerufen threaded_var
, außer für den Thread, der beendet wird (hier der primäre Thread). Daher sollte code nicht auf die ordnungsgemäße Zerstörung von threadprivate
Variablen zählen.
Weitere Informationen finden Sie unter der Threadprivate-Direktive 2.7.1.
Beispiel
Ein Beispiel für die Verwendung threadprivate
finden Sie unter "Privat".