Cláusulas OpenMP

Fornece links para as cláusulas usadas na API OpenMP.

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

Para atributos gerais:

Cláusula Descrição
if Especifica se um loop deve ser executado em paralelo ou em série.
num_threads Define o número de threads em uma equipe de threads.
ordenado Exigido em uma instrução for paralela se uma diretiva ordered deve ser usada no loop.
schedule Aplica-se à diretiva for.
nowait Substitui a barreira implícita em uma diretiva.

Para atributos de compartilhamento de dados:

Cláusula Descrição
private Especifica que cada thread deve ter a própria instância de uma variável.
firstprivate Especifica que cada thread deve ter sua própria instância de uma variável e que a variável deve ser inicializada com o valor da variável, pois ela existe antes do constructo paralelo.
lastprivate Especifica que a versão da variável do contexto delimitador é definida como a versão privada de qualquer thread que execute a iteração final (constructo for-loop) ou a última seção (seções #pragma).
shared Especifica que uma ou mais variáveis devem ser compartilhadas entre todos os threads.
default Especifica o comportamento de variáveis sem escopo em uma região paralela.
reduction Especifica que uma ou mais variáveis privadas para cada thread são objeto de uma operação de redução no final da região paralela.
copyin Permite que os threads acessem o valor do thread principal para uma variável threadprivate.
copyprivate Especifica que uma ou mais variáveis devem ser compartilhadas entre todos os threads.

copyin

Permite que os threads acessem o valor do thread principal para uma variável threadprivate.

copyin(var)

Parâmetros

var
A variável threadprivate que será inicializada com o valor da variável no thread principal, pois ela existe antes do constructo paralelo.

Comentários

copyin aplica-se às seguintes diretivas:

Para obter mais informações, confira 2.7.2.7 copyin.

Exemplo

Confira threadprivate para obter um exemplo de uso de copyin.

copyprivate

Especifica que uma ou mais variáveis devem ser compartilhadas entre todos os threads.

copyprivate(var)

Parâmetros

var
Uma ou mais variáveis a serem compartilhadas. Se mais de uma variável for especificada, separe nomes de variáveis com uma vírgula.

Comentários

copyprivate aplica-se à diretiva single.

Para obter mais informações, confira 2.7.2.8 copyprivate.

Exemplo

// omp_copyprivate.cpp
// compile with: /openmp
#include <stdio.h>
#include <omp.h>

float x, y, fGlobal = 1.0;
#pragma omp threadprivate(x, y)

float get_float() {
   fGlobal += 0.001;
   return fGlobal;
}

void use_float(float f, int t) {
   printf_s("Value = %f, thread = %d\n", f, t);
}

void CopyPrivate(float a, float b) {
   #pragma omp single copyprivate(a, b, x, y)
   {
      a = get_float();
      b = get_float();
      x = get_float();
      y = get_float();
    }

   use_float(a, omp_get_thread_num());
   use_float(b, omp_get_thread_num());
   use_float(x, omp_get_thread_num());
   use_float(y, omp_get_thread_num());
}

int main() {
   float a = 9.99, b = 123.456;

   printf_s("call CopyPrivate from a single thread\n");
   CopyPrivate(9.99, 123.456);

   printf_s("call CopyPrivate from a parallel region\n");
   #pragma omp parallel
   {
      CopyPrivate(a, b);
   }
}
call CopyPrivate from a single thread
Value = 1.001000, thread = 0
Value = 1.002000, thread = 0
Value = 1.003000, thread = 0
Value = 1.004000, thread = 0
call CopyPrivate from a parallel region
Value = 1.005000, thread = 0
Value = 1.005000, thread = 1
Value = 1.006000, thread = 0
Value = 1.006000, thread = 1
Value = 1.007000, thread = 0
Value = 1.007000, thread = 1
Value = 1.008000, thread = 0
Value = 1.008000, thread = 1

default

Especifica o comportamento de variáveis sem escopo em uma região paralela.

default(shared | none)

Comentários

shared, que estará em vigor se a cláusula default não for especificada, significa que qualquer variável em uma região paralela será tratada como se tivesse sido especificada com a cláusula shared. none significa que todas as variáveis usadas em uma região paralela que não têm escopo com a cláusula private, shared, reduction, firstprivate ou lastprivate causarão um erro do compilador.

default aplica-se às seguintes diretivas:

Para obter mais informações, confira 2.7.2.5 default.

Exemplo

Confira private para obter um exemplo de uso de default.

firstprivate

Especifica que cada thread deve ter sua própria instância de uma variável e que a variável deve ser inicializada com o valor da variável, pois ela existe antes do constructo paralelo.

firstprivate(var)

Parâmetros

var
A variável a ter instâncias em cada thread e que serão inicializadas com o valor da variável, pois ela existe antes do constructo paralelo. Se mais de uma variável for especificada, separe nomes de variáveis com uma vírgula.

Comentários

firstprivate aplica-se às seguintes diretivas:

Para obter mais informações, confira 2.7.2.2 firstprivate.

Exemplo

Para obter um exemplo de uso de firstprivate, confira o exemplo em private.

if (OpenMP)

Especifica se um loop deve ser executado em paralelo ou em série.

if(expression)

Parâmetros

expressão
Uma expressão integral que, se avaliada como true (diferente de zero), fará com que o código na região paralela seja executado em paralelo. Se a expressão for avaliada como false (zero), a região paralela será executada em série (por apenas um thread).

Comentários

if aplica-se às seguintes diretivas:

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

Exemplo

// omp_if.cpp
// compile with: /openmp
#include <stdio.h>
#include <omp.h>

void test(int val)
{
    #pragma omp parallel if (val)
    if (omp_in_parallel())
    {
        #pragma omp single
        printf_s("val = %d, parallelized with %d threads\n",
                 val, omp_get_num_threads());
    }
    else
    {
        printf_s("val = %d, serialized\n", val);
    }
}

int main( )
{
    omp_set_num_threads(2);
    test(0);
    test(2);
}
val = 0, serialized
val = 2, parallelized with 2 threads

lastprivate

Especifica que a versão da variável do contexto delimitador é definida como a versão privada de qualquer thread que execute a iteração final (constructo for-loop) ou a última seção (seções #pragma).

lastprivate(var)

Parâmetros

var
A variável que é definida como a versão privada de qualquer thread que execute a iteração final (constructo for-loop) ou a última seção (seções #pragma).

Comentários

lastprivate aplica-se às seguintes diretivas:

Para obter mais informações, confira 2.7.2.3 lastprivate.

Exemplo

Confira schedule para obter um exemplo de uso da cláusula lastprivate.

nowait

Substitui a barreira implícita em uma diretiva.

nowait

Comentários

nowait aplica-se às seguintes diretivas:

Para obter mais informações, confira 2.4.1 constructo for, constructo sections 2.4.2 e 2.4.3 constructo single.

Exemplo

// omp_nowait.cpp
// compile with: /openmp /c
#include <stdio.h>

#define SIZE 5

void test(int *a, int *b, int *c, int size)
{
    int i;
    #pragma omp parallel
    {
        #pragma omp for nowait
        for (i = 0; i < size; i++)
            b[i] = a[i] * a[i];

        #pragma omp for nowait
        for (i = 0; i < size; i++)
            c[i] = a[i]/2;
    }
}

int main( )
{
    int a[SIZE], b[SIZE], c[SIZE];
    int i;

    for (i=0; i<SIZE; i++)
        a[i] = i;

    test(a,b,c, SIZE);

    for (i=0; i<SIZE; i++)
        printf_s("%d, %d, %d\n", a[i], b[i], c[i]);
}
0, 0, 0
1, 1, 0
2, 4, 1
3, 9, 1
4, 16, 2

num_threads

Define o número de threads em uma equipe de threads.

num_threads(num)

Parâmetros

num
O número de threads

Comentários

A cláusula num_threads tem a mesma funcionalidade que a função omp_set_num_threads.

num_threads aplica-se às seguintes diretivas:

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

Exemplo

Confira parallel para obter um exemplo de uso da cláusula num_threads.

ordered

Exigido em uma instrução for paralela se uma diretiva ordered deve ser usada no loop.

ordered

Comentários

ordered aplica-se à diretiva for.

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

Exemplo

Confira ordered para obter um exemplo de uso da cláusula ordered.

private

Especifica que cada thread deve ter a própria instância de uma variável.

private(var)

Parâmetros

var
A variável a ter instâncias em cada thread.

Comentários

private aplica-se às seguintes diretivas:

Para obter mais informações, confira 2.7.2.1 private.

Exemplo

// openmp_private.c
// compile with: /openmp
#include <windows.h>
#include <assert.h>
#include <stdio.h>
#include <omp.h>

#define NUM_THREADS 4
#define SLEEP_THREAD 1
#define NUM_LOOPS 2

enum Types {
   ThreadPrivate,
   Private,
   FirstPrivate,
   LastPrivate,
   Shared,
   MAX_TYPES
};

int nSave[NUM_THREADS][MAX_TYPES][NUM_LOOPS] = {{0}};
int nThreadPrivate;

#pragma omp threadprivate(nThreadPrivate)
#pragma warning(disable:4700)

int main() {
   int nPrivate = NUM_THREADS;
   int nFirstPrivate = NUM_THREADS;
   int nLastPrivate = NUM_THREADS;
   int nShared = NUM_THREADS;
   int nRet = 0;
   int i;
   int j;
   int nLoop = 0;

   nThreadPrivate = NUM_THREADS;
   printf_s("These are the variables before entry "
           "into the parallel region.\n");
   printf_s("nThreadPrivate = %d\n", nThreadPrivate);
   printf_s("      nPrivate = %d\n", nPrivate);
   printf_s(" nFirstPrivate = %d\n", nFirstPrivate);
   printf_s("  nLastPrivate = %d\n", nLastPrivate);
   printf_s("       nShared = %d\n\n", nShared);
   omp_set_num_threads(NUM_THREADS);

   #pragma omp parallel copyin(nThreadPrivate) private(nPrivate) shared(nShared) firstprivate(nFirstPrivate)
   {
      #pragma omp for schedule(static) lastprivate(nLastPrivate)
      for (i = 0 ; i < NUM_THREADS ; ++i) {
         for (j = 0 ; j < NUM_LOOPS ; ++j) {
            int nThread = omp_get_thread_num();
            assert(nThread < NUM_THREADS);

            if (nThread == SLEEP_THREAD)
               Sleep(100);
            nSave[nThread][ThreadPrivate][j] = nThreadPrivate;
            nSave[nThread][Private][j] = nPrivate;
            nSave[nThread][Shared][j] = nShared;
            nSave[nThread][FirstPrivate][j] = nFirstPrivate;
            nSave[nThread][LastPrivate][j] = nLastPrivate;
            nThreadPrivate = nThread;
            nPrivate = nThread;
            nShared = nThread;
            nLastPrivate = nThread;
            --nFirstPrivate;
         }
      }
   }

   for (i = 0 ; i < NUM_LOOPS ; ++i) {
      for (j = 0 ; j < NUM_THREADS ; ++j) {
         printf_s("These are the variables at entry of "
                  "loop %d of thread %d.\n", i + 1, j);
         printf_s("nThreadPrivate = %d\n",
                  nSave[j][ThreadPrivate][i]);
         printf_s("      nPrivate = %d\n",
                  nSave[j][Private][i]);
         printf_s(" nFirstPrivate = %d\n",
                  nSave[j][FirstPrivate][i]);
         printf_s("  nLastPrivate = %d\n",
                  nSave[j][LastPrivate][i]);
         printf_s("       nShared = %d\n\n",
                  nSave[j][Shared][i]);
      }
   }

   printf_s("These are the variables after exit from "
            "the parallel region.\n");
   printf_s("nThreadPrivate = %d (The last value in the "
            "main thread)\n", nThreadPrivate);
   printf_s("      nPrivate = %d (The value prior to "
            "entering parallel region)\n", nPrivate);
   printf_s(" nFirstPrivate = %d (The value prior to "
            "entering parallel region)\n", nFirstPrivate);
   printf_s("  nLastPrivate = %d (The value from the "
            "last iteration of the loop)\n", nLastPrivate);
   printf_s("       nShared = %d (The value assigned, "
            "from the delayed thread, %d)\n\n",
            nShared, SLEEP_THREAD);
}
These are the variables before entry into the parallel region.
nThreadPrivate = 4
      nPrivate = 4
nFirstPrivate = 4
  nLastPrivate = 4
       nShared = 4

These are the variables at entry of loop 1 of thread 0.
nThreadPrivate = 4
      nPrivate = 1310720
nFirstPrivate = 4
  nLastPrivate = 1245104
       nShared = 3

These are the variables at entry of loop 1 of thread 1.
nThreadPrivate = 4
      nPrivate = 4488
nFirstPrivate = 4
  nLastPrivate = 19748
       nShared = 0

These are the variables at entry of loop 1 of thread 2.
nThreadPrivate = 4
      nPrivate = -132514848
nFirstPrivate = 4
  nLastPrivate = -513199792
       nShared = 4

These are the variables at entry of loop 1 of thread 3.
nThreadPrivate = 4
      nPrivate = 1206
nFirstPrivate = 4
  nLastPrivate = 1204
       nShared = 2

These are the variables at entry of loop 2 of thread 0.
nThreadPrivate = 0
      nPrivate = 0
nFirstPrivate = 3
  nLastPrivate = 0
       nShared = 0

These are the variables at entry of loop 2 of thread 1.
nThreadPrivate = 1
      nPrivate = 1
nFirstPrivate = 3
  nLastPrivate = 1
       nShared = 1

These are the variables at entry of loop 2 of thread 2.
nThreadPrivate = 2
      nPrivate = 2
nFirstPrivate = 3
  nLastPrivate = 2
       nShared = 2

These are the variables at entry of loop 2 of thread 3.
nThreadPrivate = 3
      nPrivate = 3
nFirstPrivate = 3
  nLastPrivate = 3
       nShared = 3

These are the variables after exit from the parallel region.
nThreadPrivate = 0 (The last value in the main thread)
      nPrivate = 4 (The value prior to entering parallel region)
nFirstPrivate = 4 (The value prior to entering parallel region)
  nLastPrivate = 3 (The value from the last iteration of the loop)
       nShared = 1 (The value assigned, from the delayed thread, 1)

superfície de ataque

Especifica que uma ou mais variáveis privadas para cada thread são objeto de uma operação de redução no final da região paralela.

reduction(operation:var)

Parâmetros

operation
O operador da operação a ser realizada nas variáveis var no final da região paralela.

var
Uma ou mais variáveis sobre as quais fazer a redução escalar. Se mais de uma variável for especificada, separe nomes de variáveis com uma vírgula.

Comentários

reduction aplica-se às seguintes diretivas:

Para obter mais informações, confira 2.7.2.6 reduction.

Exemplo

// omp_reduction.cpp
// compile with: /openmp
#include <stdio.h>
#include <omp.h>

#define NUM_THREADS 4
#define SUM_START   1
#define SUM_END     10
#define FUNC_RETS   {1, 1, 1, 1, 1}

int bRets[5] = FUNC_RETS;
int nSumCalc = ((SUM_START + SUM_END) * (SUM_END - SUM_START + 1)) / 2;

int func1( ) {return bRets[0];}
int func2( ) {return bRets[1];}
int func3( ) {return bRets[2];}
int func4( ) {return bRets[3];}
int func5( ) {return bRets[4];}

int main( )
{
    int nRet = 0,
        nCount = 0,
        nSum = 0,
        i,
        bSucceed = 1;

    omp_set_num_threads(NUM_THREADS);

    #pragma omp parallel reduction(+ : nCount)
    {
        nCount += 1;

        #pragma omp for reduction(+ : nSum)
        for (i = SUM_START ; i <= SUM_END ; ++i)
            nSum += i;

        #pragma omp sections reduction(&& : bSucceed)
        {
            #pragma omp section
            {
                bSucceed = bSucceed && func1( );
            }

            #pragma omp section
            {
                bSucceed = bSucceed && func2( );
            }

            #pragma omp section
            {
                bSucceed = bSucceed && func3( );
            }

            #pragma omp section
            {
                bSucceed = bSucceed && func4( );
            }

            #pragma omp section
            {
                bSucceed = bSucceed && func5( );
            }
        }
    }

    printf_s("The parallel section was executed %d times "
             "in parallel.\n", nCount);
    printf_s("The sum of the consecutive integers from "
             "%d to %d, is %d\n", 1, 10, nSum);

    if (bSucceed)
        printf_s("All of the functions, func1 through "
                 "func5 succeeded!\n");
    else
        printf_s("One or more of the functions, func1 "
                 "through func5 failed!\n");

    if (nCount != NUM_THREADS)
    {
        printf_s("ERROR: For %d threads, %d were counted!\n",
                 NUM_THREADS, nCount);
        nRet |= 0x1;
   }

    if (nSum != nSumCalc)
    {
        printf_s("ERROR: The sum of %d through %d should be %d, "
                "but %d was reported!\n",
                SUM_START, SUM_END, nSumCalc, nSum);
        nRet |= 0x10;
    }

    if (bSucceed != (bRets[0] && bRets[1] &&
                     bRets[2] && bRets[3] && bRets[4]))
    {
        printf_s("ERROR: The sum of %d through %d should be %d, "
                 "but %d was reported!\n",
                 SUM_START, SUM_END, nSumCalc, nSum);
        nRet |= 0x100;
    }
}
The parallel section was executed 4 times in parallel.
The sum of the consecutive integers from 1 to 10, is 55
All of the functions, func1 through func5 succeeded!

schedule

Aplica-se à diretiva for.

schedule(type[,size])

Parâmetros

tipo
O tipo de agendamento, seja dynamic, guidedruntime ou static.

size
(Opcional) Especifica o tamanho das iterações. size precisa ser um inteiro. Não é válido quando type é runtime.

Comentários

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

Exemplo

// omp_schedule.cpp
// compile with: /openmp
#include <windows.h>
#include <stdio.h>
#include <omp.h>

#define NUM_THREADS 4
#define STATIC_CHUNK 5
#define DYNAMIC_CHUNK 5
#define NUM_LOOPS 20
#define SLEEP_EVERY_N 3

int main( )
{
    int nStatic1[NUM_LOOPS],
        nStaticN[NUM_LOOPS];
    int nDynamic1[NUM_LOOPS],
        nDynamicN[NUM_LOOPS];
    int nGuided[NUM_LOOPS];

    omp_set_num_threads(NUM_THREADS);

    #pragma omp parallel
    {
        #pragma omp for schedule(static, 1)
        for (int i = 0 ; i < NUM_LOOPS ; ++i)
        {
            if ((i % SLEEP_EVERY_N) == 0)
                Sleep(0);
            nStatic1[i] = omp_get_thread_num( );
        }

        #pragma omp for schedule(static, STATIC_CHUNK)
        for (int i = 0 ; i < NUM_LOOPS ; ++i)
        {
            if ((i % SLEEP_EVERY_N) == 0)
                Sleep(0);
            nStaticN[i] = omp_get_thread_num( );
        }

        #pragma omp for schedule(dynamic, 1)
        for (int i = 0 ; i < NUM_LOOPS ; ++i)
        {
            if ((i % SLEEP_EVERY_N) == 0)
                Sleep(0);
            nDynamic1[i] = omp_get_thread_num( );
        }

        #pragma omp for schedule(dynamic, DYNAMIC_CHUNK)
        for (int i = 0 ; i < NUM_LOOPS ; ++i)
        {
            if ((i % SLEEP_EVERY_N) == 0)
                Sleep(0);
            nDynamicN[i] = omp_get_thread_num( );
        }

        #pragma omp for schedule(guided)
        for (int i = 0 ; i < NUM_LOOPS ; ++i)
        {
            if ((i % SLEEP_EVERY_N) == 0)
                Sleep(0);
            nGuided[i] = omp_get_thread_num( );
        }
    }

    printf_s("------------------------------------------------\n");
    printf_s("| static | static | dynamic | dynamic | guided |\n");
    printf_s("|    1   |    %d   |    1    |    %d    |        |\n",
             STATIC_CHUNK, DYNAMIC_CHUNK);
    printf_s("------------------------------------------------\n");

    for (int i=0; i<NUM_LOOPS; ++i)
    {
        printf_s("|    %d   |    %d   |    %d    |    %d    |"
                 "    %d   |\n",
                 nStatic1[i], nStaticN[i],
                 nDynamic1[i], nDynamicN[i], nGuided[i]);
    }

    printf_s("------------------------------------------------\n");
}
------------------------------------------------
| static | static | dynamic | dynamic | guided |
|    1   |    5   |    1    |    5    |        |
------------------------------------------------
|    0   |    0   |    0    |    2    |    1   |
|    1   |    0   |    3    |    2    |    1   |
|    2   |    0   |    3    |    2    |    1   |
|    3   |    0   |    3    |    2    |    1   |
|    0   |    0   |    2    |    2    |    1   |
|    1   |    1   |    2    |    3    |    3   |
|    2   |    1   |    2    |    3    |    3   |
|    3   |    1   |    0    |    3    |    3   |
|    0   |    1   |    0    |    3    |    3   |
|    1   |    1   |    0    |    3    |    2   |
|    2   |    2   |    1    |    0    |    2   |
|    3   |    2   |    1    |    0    |    2   |
|    0   |    2   |    1    |    0    |    3   |
|    1   |    2   |    2    |    0    |    3   |
|    2   |    2   |    2    |    0    |    0   |
|    3   |    3   |    2    |    1    |    0   |
|    0   |    3   |    3    |    1    |    1   |
|    1   |    3   |    3    |    1    |    1   |
|    2   |    3   |    3    |    1    |    1   |
|    3   |    3   |    0    |    1    |    3   |
------------------------------------------------

shared

Especifica que uma ou mais variáveis devem ser compartilhadas entre todos os threads.

shared(var)

Parâmetros

var
Uma ou mais variáveis a serem compartilhadas. Se mais de uma variável for especificada, separe nomes de variáveis com uma vírgula.

Comentários

Outra maneira de compartilhar variáveis entre threads é com a cláusula copyprivate.

shared aplica-se às seguintes diretivas:

Para obter mais informações, confira 2.7.2.4 shared.

Exemplo

Confira private para obter um exemplo de uso de shared.