Diretivas (OpenMP)

Fornece links para as diretivas usadas na API OpenMP.

O Visual C++ dá suporte às diretivas OpenMP a seguir.

Para compartilhamento de trabalho paralelo:

Diretiva Descrição
parallel Define uma região paralela, que é o código que será executado por vários threads em paralelo.
for Faz com que o trabalho feito em um loop for dentro de uma região paralela seja dividido entre threads.
sections Identifica seções de código a serem divididas entre todos os threads.
single Permite especificar que uma seção de código deve ser executada em apenas um thread, não necessariamente no thread principal.

Para thread principal e sincronização:

Diretiva Descrição
mestre Especifica que somente o thread principal deve executar uma seção do programa.
crítico Especifica que o código só é executado em um thread por vez.
barrier Sincroniza todos os threads em uma equipe; todos os threads pausam na barreira até que todos os threads executem a barreira.
atomic Especifica que um local de memória será atualizado atomicamente.
flush Especifica que todos os threads têm a mesma exibição de memória para todos os objetos compartilhados.
ordenado Especifica que o código em um loop paralelizado for deve ser executado como um loop sequencial.

Para ambiente de dados:

Diretiva Descrição
threadprivate Especifica que uma variável é privada para um thread.

atomic

Especifica que um local de memória será atualizado atomicamente.

#pragma omp atomic
   expression

Parâmetros

expressão
A instrução que tem o lvalue, cujo local de memória você deseja proteger contra mais de uma gravação.

Comentários

A diretiva atomic não dá suporte a nenhuma cláusula.

Para obter mais informações, confira 2.6.4 constructo atomic.

Exemplo

// 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 os threads em uma equipe; todos os threads pausam na barreira até que todos os threads executem a barreira.

#pragma omp barrier

Comentários

A diretiva barrier não dá suporte a nenhuma cláusula.

Para obter mais informações, confira 2.6.3 diretiva de barreira.

Exemplo

Para obter uma amostra de como usar barrier, confira master.

crítico

Especifica que o código só é executado em um thread por vez.

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

Parâmetros

name
(Opcional) Um nome para identificar o código crítico. O nome precisa ser incluído entre parênteses.

Comentários

A diretiva critical não dá suporte a nenhuma cláusula.

Para obter mais informações, confira 2.6.2 constructo critical.

Exemplo

// 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 os threads têm a mesma exibição de memória para todos os objetos compartilhados.

#pragma omp flush [(var)]

Parâmetros

var
(Opcional) Uma lista separada por vírgulas de variáveis que representam objetos que você deseja sincronizar. Se var não for especificado, toda a memória será liberada.

Comentários

A diretiva flush não dá suporte a nenhuma cláusula.

Para obter mais informações, confira 2.6.5 diretiva flush.

Exemplo

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

Faz com que o trabalho feito em um loop for dentro de uma região paralela seja dividido entre threads.

#pragma omp [parallel] for [clauses]
   for_statement

Parâmetros

clauses
(Opcional) Zero ou mais cláusulas, confira a seção Comentários.

for_statement
Um loop for. O comportamento indefinido resultará se o código do usuário no loop for alterar a variável de índice.

Comentários

A diretiva for dá suporte às seguintes cláusulas:

Se parallel também for especificado, clauses poderá ser qualquer cláusula aceita pelas diretivas parallel ou for, exceto nowait.

Para obter mais informações, confira 2.4.1 constructo for.

Exemplo

// 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 somente o thread principal deve executar uma seção do programa.

#pragma omp master
{
   code_block
}

Comentários

A diretiva master não dá suporte a nenhuma cláusula.

Para obter mais informações, confira 2.6.1 constructo master.

Para especificar que uma seção de código deve ser executada em apenas um thread, não necessariamente no thread principal, use em vez disso a diretiva single.

Exemplo

// 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 o código em um loop paralelizado for deve ser executado como um loop sequencial.

#pragma omp ordered
   structured-block

Comentários

A diretiva ordered precisa estar dentro da extensão dinâmica de um constructo for ou parallel for com uma cláusula ordered.

A diretiva ordered não dá suporte a nenhuma cláusula.

Para obter mais informações, confira 2.6.6 constructo ordered.

Exemplo

// 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 uma região paralela, que é o código que será executado por vários threads em paralelo.

#pragma omp parallel [clauses]
{
   code_block
}

Parâmetros

clauses
(Opcional) Zero ou mais cláusulas, confira a seção Comentários.

Comentários

A diretiva parallel dá suporte às seguintes cláusulas:

parallel também pode ser usado com as diretivas for e sections.

Para obter mais informações, confira 2.3 constructo parallel.

Exemplo

O exemplo a seguir mostra como definir o número de threads e definir uma região paralela. O número de threads é igual por padrão ao número de processadores lógicos no computador. Por exemplo, se você tiver um computador com um processador físico habilitado para hiperthreading, ele terá dois processadores lógicos e dois threads. A ordem de saída pode variar em computadores diferentes.

// 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 seções de código a serem divididas entre todos os threads.

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

Parâmetros

clauses
(Opcional) Zero ou mais cláusulas, confira a seção Comentários.

Comentários

A diretiva sections pode conter zero ou mais diretivas section.

A diretiva sections dá suporte às seguintes cláusulas:

Se parallel também for especificado, clauses poderá ser qualquer cláusula aceita pelas diretivas parallel ou sections, exceto nowait.

Para obter mais informações, confira 2.4.2 constructo sections.

Exemplo

// 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 uma seção de código deve ser executada em apenas um thread, não necessariamente no thread principal.

#pragma omp single [clauses]
{
   code_block
}

Parâmetros

clauses
(Opcional) Zero ou mais cláusulas, confira a seção Comentários.

Comentários

A diretiva single dá suporte às seguintes cláusulas:

Para obter mais informações, confira 2.4.3 constructo single.

Para especificar que uma seção de código só deve ser executada no thread principal, use a diretiva master.

Exemplo

// 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 uma variável é privada para um thread.

#pragma omp threadprivate(var)

Parâmetros

var
Uma lista separada por vírgulas de variáveis que você deseja tornar privadas para um thread. var precisa ser uma variável global ou com escopo de namespace ou uma variável estática local.

Comentários

A diretiva threadprivate não dá suporte a nenhuma cláusula.

A diretiva threadprivate baseia-se no atributo thread usando a palavra-chave __declspec; os limites em __declspec(thread) aplicam-se a threadprivate. Por exemplo, uma variável threadprivate existirá em qualquer thread iniciado no processo, não apenas nos threads que fazem parte de uma equipe de threads gerada por uma região paralela. Esteja ciente deste detalhe de implementação; você pode observar que os construtores para um tipo threadprivate definido pelo usuário são chamados com mais frequência do que o esperado.

Você pode usar threadprivate em uma DLL carregada estaticamente na inicialização do processo, no entanto, não é possível usar threadprivate em nenhuma DLL que será carregada por meio de LoadLibrary, como DLLs carregadas com /DELAYLOAD (importação de carga com atraso), que também usa LoadLibrary.

Não há garantia de que uma variável threadprivate de um tipo destructible tenha o respectivo destruidor chamado. Por exemplo:

struct MyType
{
    ~MyType();
};

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

Os usuários não têm controle sobre quando os threads que constituem a região paralela serão encerrados. Se esses threads existirem quando o processo for encerrado, os threads não serão notificados sobre a saída do processo e o destruidor não será chamado para threaded_var em nenhum thread, exceto aquele que sair (aqui, o thread primário). Portanto, o código não deve contar com a destruição adequada de variáveis threadprivate.

Para obter mais informações, confira 2.7.1 diretiva threadprivate.

Exemplo

Para obter um exemplo de uso de threadprivate, confira private.