Direttive OpenMP
Fornisce collegamenti alle direttive usate nell'API OpenMP.
Visual C++ supporta le direttive OpenMP seguenti.
Per la condivisione di lavoro parallela:
Direttiva | Descrizione |
---|---|
parallel | Definisce un'area parallela, ovvero codice che verrà eseguito da più thread in parallelo. |
for | Fa in modo che il lavoro eseguito in un for ciclo all'interno di un'area parallela venga diviso tra i thread. |
sections | Identifica le sezioni di codice da dividere tra tutti i thread. |
single | Consente di specificare che una sezione di codice deve essere eseguita su un singolo thread, non necessariamente il thread principale. |
Per il thread principale e la sincronizzazione:
Direttiva | Descrizione |
---|---|
master | Specifica che solo il thread principale deve eseguire una sezione del programma. |
critical | Specifica che il codice viene eseguito solo su un thread alla volta. |
barrier | Sincronizza tutti i thread in un team; tutti i thread si sospendono sulla barriera, fino a quando tutti i thread non eseguono la barriera. |
atomic | Specifica che una posizione di memoria che verrà aggiornata in modo atomico. |
flush | Specifica che tutti i thread hanno la stessa visualizzazione della memoria per tutti gli oggetti condivisi. |
ordinato | Specifica che il codice in un ciclo parallelizzato for deve essere eseguito come un ciclo sequenziale. |
Per l'ambiente dati:
Direttiva | Descrizione |
---|---|
threadprivate | Specifica che una variabile è privata per un thread. |
atomic
Specifica che una posizione di memoria che verrà aggiornata in modo atomico.
#pragma omp atomic
expression
Parametri
expression
Istruzione con lvalue, la cui posizione di memoria si vuole proteggere da più di una scrittura.
Osservazioni:
La atomic
direttiva non supporta clausole.
Per altre informazioni, vedere Costrutto atomico 2.6.4.
Esempio
// 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
Sincronizza tutti i thread in un team; tutti i thread si sospendono sulla barriera, fino a quando tutti i thread non eseguono la barriera.
#pragma omp barrier
Osservazioni:
La barrier
direttiva non supporta clausole.
Per altre informazioni, vedere direttiva barriera 2.6.3.
Esempio
Per un esempio di come usare barrier
, vedere master.
critical
Specifica che il codice viene eseguito solo su un thread alla volta.
#pragma omp critical [(name)]
{
code_block
}
Parametri
name
(Facoltativo) Nome per identificare il codice critico. Il nome deve essere racchiuso tra parentesi.
Osservazioni:
La critical
direttiva non supporta clausole.
Per altre informazioni, vedere Costrutto critico 2.6.2.
Esempio
// 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
Specifica che tutti i thread hanno la stessa visualizzazione della memoria per tutti gli oggetti condivisi.
#pragma omp flush [(var)]
Parametri
var
(Facoltativo) Elenco delimitato da virgole di variabili che rappresentano gli oggetti da sincronizzare. Se var non è specificato, tutta la memoria viene scaricata.
Osservazioni:
La flush
direttiva non supporta clausole.
Per altre informazioni, vedere direttiva flush 2.6.5.
Esempio
// 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
for
Fa in modo che il lavoro eseguito in un for
ciclo all'interno di un'area parallela venga diviso tra i thread.
#pragma omp [parallel] for [clauses]
for_statement
Parametri
Clausole
(Facoltativo) Zero o più clausole, vedere la sezione Osservazioni .
for_statement
Ciclo .for
Il comportamento non definito genererà se il codice utente nel for
ciclo modifica la variabile di indice.
Osservazioni:
La for
direttiva supporta le clausole seguenti:
Se parallel
viene specificato anche , clauses
può essere qualsiasi clausola accettata dalle parallel
direttive o for
, ad eccezione di nowait
.
Per altre informazioni, vedere 2.4.1 per costrutto.
Esempio
// 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
Specifica che solo il thread principale deve eseguire una sezione del programma.
#pragma omp master
{
code_block
}
Osservazioni:
La master
direttiva non supporta clausole.
Per altre informazioni, vedere 2.6.1 costrutto master.
Per specificare che una sezione di codice deve essere eseguita in un singolo thread, non necessariamente nel thread principale, usare invece la singola direttiva.
Esempio
// 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
Specifica che il codice in un ciclo parallelizzato for
deve essere eseguito come un ciclo sequenziale.
#pragma omp ordered
structured-block
Osservazioni:
La ordered
direttiva deve trovarsi all'interno dell'extent dinamico di un oggetto per o parallel for
di un costrutto con una ordered
clausola .
La ordered
direttiva non supporta clausole.
Per altre informazioni, vedere Costrutto ordinato 2.6.6.
Esempio
// 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
Definisce un'area parallela, ovvero codice che verrà eseguito da più thread in parallelo.
#pragma omp parallel [clauses]
{
code_block
}
Parametri
Clausole
(Facoltativo) Zero o più clausole, vedere la sezione Osservazioni .
Osservazioni:
La parallel
direttiva supporta le clausole seguenti:
parallel
può essere usato anche con le direttive for e sections .
Per altre informazioni, vedere Costrutto parallelo 2.3.
Esempio
L'esempio seguente illustra come impostare il numero di thread e definire un'area parallela. Il numero di thread è uguale per impostazione predefinita al numero di processori logici nel computer. Ad esempio, se si dispone di un computer con un processore fisico con hyperthreading abilitato, avrà due processori logici e due thread. L'ordine di output può variare in computer diversi.
// 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
Identifica le sezioni di codice da dividere tra tutti i thread.
#pragma omp [parallel] sections [clauses]
{
#pragma omp section
{
code_block
}
}
Parametri
Clausole
(Facoltativo) Zero o più clausole, vedere la sezione Osservazioni .
Osservazioni:
La sections
direttiva può contenere zero o più section
direttive.
La sections
direttiva supporta le clausole seguenti:
Se parallel
viene specificato anche , clauses
può essere qualsiasi clausola accettata dalle parallel
direttive o sections
, ad eccezione di nowait
.
Per altre informazioni, vedere costrutto delle sezioni 2.4.2.
Esempio
// 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
singolo
Consente di specificare che una sezione di codice deve essere eseguita su un singolo thread, non necessariamente il thread principale.
#pragma omp single [clauses]
{
code_block
}
Parametri
Clausole
(Facoltativo) Zero o più clausole, vedere la sezione Osservazioni .
Osservazioni:
La single
direttiva supporta le clausole seguenti:
Per altre informazioni, vedere 2.4.3 costrutto singolo.
Per specificare che una sezione di codice deve essere eseguita solo nel thread principale, usare invece la direttiva master .
Esempio
// 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
Specifica che una variabile è privata per un thread.
#pragma omp threadprivate(var)
Parametri
var
Elenco delimitato da virgole di variabili che si desidera rendere private in un thread. var deve essere una variabile globale o con ambito spazio dei nomi o una variabile statica locale.
Osservazioni:
La threadprivate
direttiva non supporta clausole.
La threadprivate
direttiva si basa sull'attributo del thread usando la parola chiave __declspec ; i limiti applicati a __declspec(thread)
si applicano a threadprivate
. Ad esempio, una threadprivate
variabile esisterà in qualsiasi thread avviato nel processo, non solo in quelli che fanno parte di un team di thread generato da un'area parallela. Tenere presente questo dettaglio di implementazione; è possibile notare che i costruttori per un threadprivate
tipo definito dall'utente vengono chiamati più spesso previsti.
È possibile usare threadprivate
in una DLL caricata in modo statico all'avvio del processo, ma non è possibile usare threadprivate
in alcuna DLL che verrà caricata tramite LoadLibrary , ad esempio dll caricate con /DELAYLOAD (importazione di caricamento ritardato) che usa LoadLibrary
anche .
Non threadprivate
è garantito che una variabile di un tipo distruttore abbia chiamato il distruttore. Ad esempio:
struct MyType
{
~MyType();
};
MyType threaded_var;
#pragma omp threadprivate(threaded_var)
int main()
{
#pragma omp parallel
{}
}
Gli utenti non hanno alcun controllo su quando i thread che costituiscono l'area parallela termineranno. Se questi thread sono presenti quando il processo viene chiuso, i thread non riceveranno una notifica sull'uscita del processo e il distruttore non verrà chiamato per threaded_var
in alcun thread, ad eccezione di quello che esce (in questo caso, il thread primario). Pertanto, il codice non deve contare sulla corretta distruzione delle threadprivate
variabili.
Per altre informazioni, vedere direttiva threadprivate 2.7.1.
Esempio
Per un esempio di uso threadprivate
di , vedere private.