Condividi tramite


Direttive OpenMP

Fornisce collegamenti alle direttive usate nell'API OpenMP.

Visual C++ supporta le direttive OpenMP seguenti.

Per la condivisione di lavoro parallela:

Direttiva Descrizione
parallel Definisce un'area parallela, ovvero codice che verrà eseguito da più thread in parallelo.
for Fa in modo che il lavoro eseguito in un for ciclo all'interno di un'area parallela venga diviso tra i thread.
sections Identifica le sezioni di codice da dividere tra tutti i thread.
single Consente di specificare che una sezione di codice deve essere eseguita su un singolo thread, non necessariamente il thread principale.

Per il thread principale e la sincronizzazione:

Direttiva Descrizione
master Specifica che solo il thread principale deve eseguire una sezione del programma.
critical Specifica che il codice viene eseguito solo su un thread alla volta.
barrier Sincronizza tutti i thread in un team; tutti i thread si sospendono sulla barriera, fino a quando tutti i thread non eseguono la barriera.
atomic Specifica che una posizione di memoria che verrà aggiornata in modo atomico.
flush Specifica che tutti i thread hanno la stessa visualizzazione della memoria per tutti gli oggetti condivisi.
ordinato Specifica che il codice in un ciclo parallelizzato for deve essere eseguito come un ciclo sequenziale.

Per l'ambiente dati:

Direttiva Descrizione
threadprivate Specifica che una variabile è privata per un thread.

atomic

Specifica che una posizione di memoria che verrà aggiornata in modo atomico.

#pragma omp atomic
   expression

Parametri

expression
Istruzione con lvalue, la cui posizione di memoria si vuole proteggere da più di una scrittura.

Osservazioni:

La atomic direttiva non supporta clausole.

Per altre informazioni, vedere Costrutto atomico 2.6.4.

Esempio

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

Sincronizza tutti i thread in un team; tutti i thread si sospendono sulla barriera, fino a quando tutti i thread non eseguono la barriera.

#pragma omp barrier

Osservazioni:

La barrier direttiva non supporta clausole.

Per altre informazioni, vedere direttiva barriera 2.6.3.

Esempio

Per un esempio di come usare barrier, vedere master.

critical

Specifica che il codice viene eseguito solo su un thread alla volta.

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

Parametri

name
(Facoltativo) Nome per identificare il codice critico. Il nome deve essere racchiuso tra parentesi.

Osservazioni:

La critical direttiva non supporta clausole.

Per altre informazioni, vedere Costrutto critico 2.6.2.

Esempio

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

Specifica che tutti i thread hanno la stessa visualizzazione della memoria per tutti gli oggetti condivisi.

#pragma omp flush [(var)]

Parametri

var
(Facoltativo) Elenco delimitato da virgole di variabili che rappresentano gli oggetti da sincronizzare. Se var non è specificato, tutta la memoria viene scaricata.

Osservazioni:

La flush direttiva non supporta clausole.

Per altre informazioni, vedere direttiva flush 2.6.5.

Esempio

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

Fa in modo che il lavoro eseguito in un for ciclo all'interno di un'area parallela venga diviso tra i thread.

#pragma omp [parallel] for [clauses]
   for_statement

Parametri

Clausole
(Facoltativo) Zero o più clausole, vedere la sezione Osservazioni .

for_statement
Ciclo .for Il comportamento non definito genererà se il codice utente nel for ciclo modifica la variabile di indice.

Osservazioni:

La for direttiva supporta le clausole seguenti:

Se parallel viene specificato anche , clauses può essere qualsiasi clausola accettata dalle parallel direttive o for , ad eccezione di nowait.

Per altre informazioni, vedere 2.4.1 per costrutto.

Esempio

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

Specifica che solo il thread principale deve eseguire una sezione del programma.

#pragma omp master
{
   code_block
}

Osservazioni:

La master direttiva non supporta clausole.

Per altre informazioni, vedere 2.6.1 costrutto master.

Per specificare che una sezione di codice deve essere eseguita in un singolo thread, non necessariamente nel thread principale, usare invece la singola direttiva.

Esempio

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

Specifica che il codice in un ciclo parallelizzato for deve essere eseguito come un ciclo sequenziale.

#pragma omp ordered
   structured-block

Osservazioni:

La ordered direttiva deve trovarsi all'interno dell'extent dinamico di un oggetto per o parallel for di un costrutto con una ordered clausola .

La ordered direttiva non supporta clausole.

Per altre informazioni, vedere Costrutto ordinato 2.6.6.

Esempio

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

Definisce un'area parallela, ovvero codice che verrà eseguito da più thread in parallelo.

#pragma omp parallel [clauses]
{
   code_block
}

Parametri

Clausole
(Facoltativo) Zero o più clausole, vedere la sezione Osservazioni .

Osservazioni:

La parallel direttiva supporta le clausole seguenti:

parallel può essere usato anche con le direttive for e sections .

Per altre informazioni, vedere Costrutto parallelo 2.3.

Esempio

L'esempio seguente illustra come impostare il numero di thread e definire un'area parallela. Il numero di thread è uguale per impostazione predefinita al numero di processori logici nel computer. Ad esempio, se si dispone di un computer con un processore fisico con hyperthreading abilitato, avrà due processori logici e due thread. L'ordine di output può variare in computer diversi.

// 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 le sezioni di codice da dividere tra tutti i thread.

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

Parametri

Clausole
(Facoltativo) Zero o più clausole, vedere la sezione Osservazioni .

Osservazioni:

La sections direttiva può contenere zero o più section direttive.

La sections direttiva supporta le clausole seguenti:

Se parallel viene specificato anche , clauses può essere qualsiasi clausola accettata dalle parallel direttive o sections , ad eccezione di nowait.

Per altre informazioni, vedere costrutto delle sezioni 2.4.2.

Esempio

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

singolo

Consente di specificare che una sezione di codice deve essere eseguita su un singolo thread, non necessariamente il thread principale.

#pragma omp single [clauses]
{
   code_block
}

Parametri

Clausole
(Facoltativo) Zero o più clausole, vedere la sezione Osservazioni .

Osservazioni:

La single direttiva supporta le clausole seguenti:

Per altre informazioni, vedere 2.4.3 costrutto singolo.

Per specificare che una sezione di codice deve essere eseguita solo nel thread principale, usare invece la direttiva master .

Esempio

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

Specifica che una variabile è privata per un thread.

#pragma omp threadprivate(var)

Parametri

var
Elenco delimitato da virgole di variabili che si desidera rendere private in un thread. var deve essere una variabile globale o con ambito spazio dei nomi o una variabile statica locale.

Osservazioni:

La threadprivate direttiva non supporta clausole.

La threadprivate direttiva si basa sull'attributo del thread usando la parola chiave __declspec ; i limiti applicati a __declspec(thread) si applicano a threadprivate. Ad esempio, una threadprivate variabile esisterà in qualsiasi thread avviato nel processo, non solo in quelli che fanno parte di un team di thread generato da un'area parallela. Tenere presente questo dettaglio di implementazione; è possibile notare che i costruttori per un threadprivate tipo definito dall'utente vengono chiamati più spesso previsti.

È possibile usare threadprivate in una DLL caricata in modo statico all'avvio del processo, ma non è possibile usare threadprivate in alcuna DLL che verrà caricata tramite LoadLibrary , ad esempio dll caricate con /DELAYLOAD (importazione di caricamento ritardato) che usa LoadLibraryanche .

Non threadprivate è garantito che una variabile di un tipo distruttore abbia chiamato il distruttore. Ad esempio:

struct MyType
{
    ~MyType();
};

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

Gli utenti non hanno alcun controllo su quando i thread che costituiscono l'area parallela termineranno. Se questi thread sono presenti quando il processo viene chiuso, i thread non riceveranno una notifica sull'uscita del processo e il distruttore non verrà chiamato per threaded_var in alcun thread, ad eccezione di quello che esce (in questo caso, il thread primario). Pertanto, il codice non deve contare sulla corretta distruzione delle threadprivate variabili.

Per altre informazioni, vedere direttiva threadprivate 2.7.1.

Esempio

Per un esempio di uso threadprivatedi , vedere private.