Partager via


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.
Commandé 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

name
(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

for

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 de l'__declspec mot clé ; 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é.