Directives OpenMP
Fournit des liens vers des directives utilisées dans l’API OpenMP.
Visual C++ prend en charge les directives OpenMP suivantes.
Pour le partage de travail parallèle :
Directive | Description |
---|---|
parallel | Définit une région parallèle, qui est le code qui sera exécuté par plusieurs threads en parallèle. |
for | Provoque la division du travail effectué dans une for boucle à l’intérieur d’une région parallèle entre les threads. |
sections | Identifie les sections de code à diviser entre tous les threads. |
single | Vous permet de spécifier qu’une section de code doit être exécutée sur un seul thread, pas nécessairement sur le thread principal. |
Pour le thread principal et la synchronisation :
Directive | Description |
---|---|
maître | Spécifie que seul le thread principal doit exécuter une section du programme. |
critical | Spécifie que le code est exécuté uniquement sur un thread à la fois. |
barrier | Synchronise tous les threads d’une équipe ; tous les threads s’interrompent à la barrière jusqu’à ce que tous les threads exécutent la barrière. |
atomic | Spécifie qu’un emplacement de mémoire qui sera mis à jour atomiquement. |
flush | Spécifie que tous les threads ont la même vue de mémoire pour tous les objets partagés. |
ordonné | Spécifie que le code sous une boucle parallélisée for doit être exécuté comme une boucle séquentielle. |
Pour l’environnement de données :
Directive | Description |
---|---|
threadprivate | Spécifie qu’une variable est privée à un thread. |
atomic
Spécifie qu’un emplacement de mémoire qui sera mis à jour atomiquement.
#pragma omp atomic
expression
Paramètres
expression
Instruction qui a la valeur lvalue, dont l’emplacement de mémoire que vous souhaitez protéger contre plusieurs écritures.
Notes
La atomic
directive ne prend pas en charge de clauses.
Pour plus d’informations, consultez la construction atomique 2.6.4.
Exemple
// 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
Synchronise tous les threads d’une équipe ; tous les threads s’interrompent à la barrière jusqu’à ce que tous les threads exécutent la barrière.
#pragma omp barrier
Notes
La barrier
directive ne prend pas en charge de clauses.
Pour plus d’informations, consultez la directive de barrière 2.6.3.
Exemple
Pour obtenir un exemple d’utilisation barrier
, consultez master.
critical
Spécifie que le code n’est exécuté que sur un thread à la fois.
#pragma omp critical [(name)]
{
code_block
}
Paramètres
nom
(Facultatif) Nom permettant d’identifier le code critique. Le nom doit être placé entre parenthèses.
Notes
La critical
directive ne prend pas en charge de clauses.
Pour plus d’informations, consultez la construction critique 2.6.2.
Exemple
// 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
Spécifie que tous les threads ont la même vue de mémoire pour tous les objets partagés.
#pragma omp flush [(var)]
Paramètres
var
(Facultatif) Liste séparée par des virgules de variables qui représentent des objets que vous souhaitez synchroniser. Si var n’est pas spécifié, toute la mémoire est vidée.
Notes
La flush
directive ne prend pas en charge de clauses.
Pour plus d’informations, consultez la directive de vidage 2.6.5.
Exemple
// 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
pour
Provoque la division du travail effectué dans une for
boucle à l’intérieur d’une région parallèle entre les threads.
#pragma omp [parallel] for [clauses]
for_statement
Paramètres
Clauses
(Facultatif) Zéro ou plusieurs clauses, consultez la section Remarques .
for_statement
Boucle for
. Le comportement non défini se produit si le code utilisateur de la for
boucle modifie la variable d’index.
Notes
La for
directive prend en charge les clauses suivantes :
Si parallel
elle est également spécifiée, clauses
peut être n’importe quelle clause acceptée par les parallel
directives, for
sauf nowait
.
Pour plus d’informations, consultez la version 2.4.1 pour la construction.
Exemple
// 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
Spécifie que seul le thread principal doit exécuter une section du programme.
#pragma omp master
{
code_block
}
Notes
La master
directive ne prend pas en charge de clauses.
Pour plus d’informations, consultez la construction principale 2.6.1.
Pour spécifier qu’une section de code doit être exécutée sur un thread unique, pas nécessairement le thread principal, utilisez plutôt la directive unique .
Exemple
// 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
Spécifie que le code sous une boucle parallélisée for
doit être exécuté comme une boucle séquentielle.
#pragma omp ordered
structured-block
Notes
La ordered
directive doit se trouver dans l’étendue dynamique d’un for ou parallel for
d’une construction avec une ordered
clause.
La ordered
directive ne prend pas en charge de clauses.
Pour plus d’informations, consultez la construction ordonnée 2.6.6.
Exemple
// 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
Définit une région parallèle, qui est le code qui sera exécuté par plusieurs threads en parallèle.
#pragma omp parallel [clauses]
{
code_block
}
Paramètres
Clauses
(Facultatif) Zéro ou plusieurs clauses, consultez la section Remarques .
Notes
La parallel
directive prend en charge les clauses suivantes :
parallel
peut également être utilisé avec les directives pour et sections .
Pour plus d’informations, consultez la construction parallèle 2.3.
Exemple
L’exemple suivant montre comment définir le nombre de threads et définir une région parallèle. Le nombre de threads est égal par défaut au nombre de processeurs logiques sur l’ordinateur. Par exemple, si vous avez une machine avec un processeur physique avec hyperthreading activé, il aura deux processeurs logiques et deux threads. L’ordre de sortie peut varier sur différents ordinateurs.
// 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
Identifie les sections de code à diviser entre tous les threads.
#pragma omp [parallel] sections [clauses]
{
#pragma omp section
{
code_block
}
}
Paramètres
Clauses
(Facultatif) Zéro ou plusieurs clauses, consultez la section Remarques .
Notes
La sections
directive peut contenir zéro ou plusieurs section
directives.
La sections
directive prend en charge les clauses suivantes :
Si parallel
elle est également spécifiée, clauses
peut être n’importe quelle clause acceptée par les parallel
directives, sections
sauf nowait
.
Pour plus d’informations, consultez la construction des sections 2.4.2.
Exemple
// 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
Vous permet de spécifier qu’une section de code doit être exécutée sur un seul thread, pas nécessairement sur le thread principal.
#pragma omp single [clauses]
{
code_block
}
Paramètres
Clauses
(Facultatif) Zéro ou plusieurs clauses, consultez la section Remarques .
Notes
La single
directive prend en charge les clauses suivantes :
Pour plus d’informations, consultez la construction unique 2.4.3.
Pour spécifier qu’une section de code ne doit être exécutée que sur le thread principal, utilisez plutôt la directive master .
Exemple
// 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
Spécifie qu’une variable est privée à un thread.
#pragma omp threadprivate(var)
Paramètres
var
Liste séparée par des virgules de variables que vous souhaitez rendre privées à un thread. var doit être une variable globale ou étendue à l’espace de noms ou une variable statique locale.
Notes
La threadprivate
directive ne prend pas en charge de clauses.
La threadprivate
directive est basée sur l’attribut de thread à l’aide du mot clé __declspec ; les limites à __declspec(thread)
appliquer à threadprivate
. Par exemple, une threadprivate
variable existe dans n’importe quel thread démarré dans le processus, pas seulement ces threads qui font partie d’une équipe de threads générés par une région parallèle. Tenez compte de ce détail de l’implémentation ; Vous remarquerez peut-être que les constructeurs d’un threadprivate
type défini par l’utilisateur sont appelés plus souvent que prévu.
Vous pouvez utiliser threadprivate
dans une DLL qui est chargée statiquement au démarrage du processus, mais vous ne pouvez pas utiliser threadprivate
dans une DLL qui sera chargée via LoadLibrary , telle que des DLL chargées avec /DELAYLOAD (importation de chargement différée) qui utilise LoadLibrary
également .
Une threadprivate
variable d’un type destructeur n’est pas garantie d’avoir son destructeur appelé. Par exemple :
struct MyType
{
~MyType();
};
MyType threaded_var;
#pragma omp threadprivate(threaded_var)
int main()
{
#pragma omp parallel
{}
}
Les utilisateurs n’ont aucun contrôle quant au moment où les threads constituant la région parallèle se termineront. Si ces threads existent lorsque le processus se termine, les threads ne sont pas avertis de la sortie du processus et le destructeur n’est pas appelé threaded_var
sur un thread, à l’exception de celui qui sort (ici, le thread principal). Par conséquent, le code ne doit pas compter sur la destruction appropriée des threadprivate
variables.
Pour plus d’informations, consultez la directive threadprivate 2.7.1.
Exemple
Pour obtenir un exemple d’utilisation threadprivate
, voir privé.