Directivas de OpenMP

Proporciona vínculos a directivas usadas en la API de OpenMP.

Visual C++ admite las siguientes directivas OpenMP.

Para uso compartido de trabajo paralelo:

Directiva Descripción
parallel Define una región paralela, que es el código que ejecutarán varios subprocesos en paralelo.
for Hace que el trabajo realizado en un bucle for dentro de una región paralela se divida entre subprocesos.
sections Identifica las secciones de código que se van a dividir entre todos los subprocesos.
single Permite especificar que se debe ejecutar una sección de código en un único subproceso, no necesariamente en el subproceso principal.

Para el subproceso principal y la sincronización:

Directiva Descripción
maestra Especifica que solo el subproceso principal debe ejecutar una sección del programa.
crítica Especifica que el código solo se ejecuta en un subproceso cada vez.
barrier Sincroniza todos los subprocesos de un equipo; todos los subprocesos se pausan en la barrera hasta que todos los subprocesos ejecutan la barrera.
atomic Especifica una ubicación de memoria que se actualizará atómicamente.
flush Especifica que todos los subprocesos tienen la misma vista de memoria para todos los objetos compartidos.
Ordenó Especifica que el código de un bucle paralelizado for debe ejecutarse como un bucle secuencial.

Para el entorno de datos:

Directiva Descripción
threadprivate Especifica que una variable es privada para un subproceso.

atomic

Especifica una ubicación de memoria que se actualizará atómicamente.

#pragma omp atomic
   expression

Parámetros

expression
Instrucción que tiene el valor lvalue, cuya ubicación de memoria desea proteger contra más de una escritura.

Comentarios

La directiva atomic no admite cláusulas.

Para obtener más información, vea 2.6.4 atomic construct.

Ejemplo

// 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

Sincroniza todos los subprocesos de un equipo; todos los subprocesos se pausan en la barrera hasta que todos los subprocesos ejecutan la barrera.

#pragma omp barrier

Comentarios

La directiva barrier no admite cláusulas.

Para obtener más información, consulte 2.6.3 barrier directive.

Ejemplo

Para obtener un ejemplo de cómo usar barrier, consulte master.

crítica

Especifica que el código solo se ejecuta en un subproceso cada vez.

#pragma omp critical [(name)]
{
   code_block
}

Parámetros

name
(Opcional) Nombre para identificar el código crítico. El nombre debe ir entre paréntesis.

Comentarios

La directiva critical no admite cláusulas.

Para obtener más información, consulte 2.6.2 critical construct.

Ejemplo

// 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

Especifica que todos los subprocesos tienen la misma vista de memoria para todos los objetos compartidos.

#pragma omp flush [(var)]

Parámetros

var
(Opcional) Lista separada por comas de variables que representan objetos que desea sincronizar. Si no se especifica var, se vacía toda la memoria.

Comentarios

La directiva flush no admite cláusulas.

Para más información, consulte 2.6.5 flush directive.

Ejemplo

// 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

Hace que el trabajo realizado en un bucle for dentro de una región paralela se divida entre subprocesos.

#pragma omp [parallel] for [clauses]
   for_statement

Parámetros

clauses
(Opcional) Cero o más cláusulas, consulte la sección Comentarios.

for_statement
Un bucle for. Se obtendrá como resultado un comportamiento sin definir si el código de usuario del bucle for cambia la variable de índice.

Comentarios

La directiva for admite las siguientes cláusulas:

Si parallel también se especifica, clauses puede ser cualquier cláusula aceptada por las directivas parallel o for, excepto nowait.

Para obtener más información, vea 2.4.1 for construct.

Ejemplo

// 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

Especifica que solo el subproceso principal debe ejecutar una sección del programa.

#pragma omp master
{
   code_block
}

Comentarios

La directiva master no admite cláusulas.

Para obtener más información, vea 2.6.1 master construct.

Para especificar que se debe ejecutar una sección de código en un único subproceso que no es necesariamente el subproceso principal, se debe usar la directiva single en su lugar.

Ejemplo

// 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

Especifica que el código de un bucle paralelizado for debe ejecutarse como un bucle secuencial.

#pragma omp ordered
   structured-block

Comentarios

La directiva ordered debe estar dentro de la extensión dinámica de un constructo for o parallel for, con una cláusula ordered.

La directiva ordered no admite cláusulas.

Para obtener más información, vea 2.6.6 ordered construct.

Ejemplo

// 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

Define una región paralela, que es el código que ejecutarán varios subprocesos en paralelo.

#pragma omp parallel [clauses]
{
   code_block
}

Parámetros

clauses
(Opcional) Cero o más cláusulas, consulte la sección Comentarios.

Comentarios

La directiva parallel admite las siguientes cláusulas:

parallel también se puede usar con las directivas for y sections.

Para obtener más información, consulte 2.3 parallel construct.

Ejemplo

En el siguiente ejemplo se muestra cómo establecer el número de subprocesos y definir una región paralela. El número de subprocesos es igual de forma predeterminada al número de procesadores lógicos de la máquina. Por ejemplo, si tiene una máquina con un procesador físico con hyperthreading habilitado, tendrá dos procesadores lógicos y dos subprocesos. El orden de salida puede variar en diferentes máquinas.

// 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

secciones

Identifica las secciones de código que se van a dividir entre todos los subprocesos.

#pragma omp [parallel] sections [clauses]
{
   #pragma omp section
   {
      code_block
   }
}

Parámetros

clauses
(Opcional) Cero o más cláusulas, consulte la sección Comentarios.

Comentarios

La directiva sections puede contener cero o más directivas section.

La directiva sections admite las siguientes cláusulas:

Si parallel también se especifica, clauses puede ser cualquier cláusula aceptada por las directivas parallel o sections, excepto nowait.

Para obtener más información, consulte 2.4.2 sections construct.

Ejemplo

// 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

Permite especificar que se debe ejecutar una sección de código en un único subproceso, no necesariamente en el subproceso principal.

#pragma omp single [clauses]
{
   code_block
}

Parámetros

clauses
(Opcional) Cero o más cláusulas, consulte la sección Comentarios.

Comentarios

La directiva single admite las siguientes cláusulas:

Para obtener más información, consulte 2.4.3 single construct.

Para especificar que una sección de código solo se debe ejecutar en el subproceso principal, use la directiva master en su lugar.

Ejemplo

// 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

Especifica que una variable es privada para un subproceso.

#pragma omp threadprivate(var)

Parámetros

var
Lista separada por comas de variables que desea que sean privadas en un subproceso. var debe ser una variable de ámbito global o de espacio de nombres, o bien una variable estática local.

Comentarios

La directiva threadprivate no admite cláusulas.

La directiva threadprivate se basa en el atributo thread, que usa la palabra clave __declspec; los límites de __declspec(thread) se aplican a threadprivate. Por ejemplo, una variable threadprivate existirá en cualquier subproceso iniciado en el proceso; no solo en los subprocesos que forman parte de un equipo de subprocesos generado por una región paralela. Tenga en cuenta este detalle de implementación; es posible que observe que los constructores de un tipo definido por el usuario threadprivate se denominan con más frecuencia de lo esperado.

Puede usar threadprivate en un archivo DLL que se carga estáticamente durante el inicio del proceso, pero no puede usar threadprivate en ningún archivo DLL que se cargará a través de LoadLibrary, como archivos DLL que se cargan con /DELAYLOAD (importación de carga retrasada), que también usa LoadLibrary.

No se garantiza que una variable threadprivate de un tipo destructible tenga llamado a su destructor. Por ejemplo:

struct MyType
{
    ~MyType();
};

MyType threaded_var;
#pragma omp threadprivate(threaded_var)
int main()
{
    #pragma omp parallel
    {}
}

Los usuarios no tienen ningún control sobre cuándo finalizarán los subprocesos que constituyen la región paralela. Si esos subprocesos existen cuando se sale del proceso, no se notificará a los subprocesos sobre la salida del proceso y no se llamará al destructor para threaded_var en ningún subproceso, excepto el que sale (aquí, el subproceso principal). Por lo tanto, el código no debe contar con la destrucción adecuada de las variables threadprivate.

Para obtener más información, consulte 2.7.1 threadprivate directive.

Ejemplo

Para obtener un ejemplo de uso de threadprivate, consulte private.