Udostępnij za pośrednictwem


OpenMP — Dyrektywy

Udostępnia linki do dyrektyw używanych w interfejsie API openMP.

Język Visual C++ obsługuje następujące dyrektywy OpenMP.

W przypadku równoległego udostępniania pracy:

Dyrektywa opis
parallel Definiuje region równoległy, czyli kod, który będzie wykonywany równolegle przez wiele wątków.
for Powoduje podzielenie pracy w for pętli wewnątrz regionu równoległego między wątki.
Sekcje Identyfikuje sekcje kodu, które mają być podzielone między wszystkie wątki.
single Pozwala określić, że sekcja kodu powinna być wykonywana w jednym wątku, a niekoniecznie głównym wątku.

W przypadku wątku głównego i synchronizacji:

Dyrektywa opis
master Określa, że tylko główny wątek powinien wykonywać sekcję programu.
critical Określa, że kod jest wykonywany tylko w jednym wątku jednocześnie.
barrier Synchronizuje wszystkie wątki w zespole; wszystkie wątki wstrzymuje się w barierze, aż wszystkie wątki wykonają barierę.
atomic Określa, że lokalizacja pamięci, która zostanie zaktualizowana niepodziealnie.
spłukiwać Określa, że wszystkie wątki mają ten sam widok pamięci dla wszystkich obiektów udostępnionych.
Zamówione Określa, że kod w pętli równoległej for powinien być wykonywany jak sekwencyjna pętla.

Dla środowiska danych:

Dyrektywa opis
threadprivate Określa, że zmienna jest prywatna dla wątku.

atomic

Określa, że lokalizacja pamięci, która zostanie zaktualizowana niepodziealnie.

#pragma omp atomic
   expression

Parametry

wyrażenie
Instrukcja zawierająca wartość lvalue, której lokalizacja pamięci ma być chroniona przed więcej niż jednym zapisem.

Uwagi

Dyrektywa atomic nie obsługuje żadnych klauzul.

Aby uzyskać więcej informacji, zobacz konstrukcja niepodzielna 2.6.4.

Przykład

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

ograniczenie

Synchronizuje wszystkie wątki w zespole; wszystkie wątki wstrzymuje się w barierze, aż wszystkie wątki wykonają barierę.

#pragma omp barrier

Uwagi

Dyrektywa barrier nie obsługuje żadnych klauzul.

Aby uzyskać więcej informacji, zobacz dyrektywa barierowa 2.6.3.

Przykład

Aby zapoznać się z przykładem używania metody barrier, zobacz master.

critical

Określa, że kod jest wykonywany tylko w jednym wątku jednocześnie.

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

Parametry

name
(Opcjonalnie) Nazwa identyfikująca kod krytyczny. Nazwa musi być ujęta w nawiasy.

Uwagi

Dyrektywa critical nie obsługuje żadnych klauzul.

Aby uzyskać więcej informacji, zobacz konstrukcja krytyczna 2.6.2.

Przykład

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

opróżnianie

Określa, że wszystkie wątki mają ten sam widok pamięci dla wszystkich obiektów udostępnionych.

#pragma omp flush [(var)]

Parametry

var
(Opcjonalnie) Rozdzielona przecinkami lista zmiennych reprezentujących obiekty, które chcesz zsynchronizować. Jeśli wartość var nie zostanie określona, zostanie opróżniona cała pamięć.

Uwagi

Dyrektywa flush nie obsługuje żadnych klauzul.

Aby uzyskać więcej informacji, zobacz dyrektywę flush 2.6.5.

Przykład

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

dla

Powoduje podzielenie pracy w for pętli wewnątrz regionu równoległego między wątki.

#pragma omp [parallel] for [clauses]
   for_statement

Parametry

Klauzule
(Opcjonalnie) Zero lub więcej klauzul, zobacz sekcję Uwagi .

for_statement
Pętla for . Niezdefiniowane zachowanie spowoduje, że kod użytkownika w for pętli zmieni zmienną indeksu.

Uwagi

Dyrektywa for obsługuje następujące klauzule:

Jeśli parallel jest również określony, clauses może być dowolną klauzulą akceptowaną przez parallel dyrektywy lub for , z wyjątkiem nowait.

Aby uzyskać więcej informacji, zobacz 2.4.1 dla konstrukcji.

Przykład

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

Określa, że tylko główny wątek powinien wykonywać sekcję programu.

#pragma omp master
{
   code_block
}

Uwagi

Dyrektywa master nie obsługuje żadnych klauzul.

Aby uzyskać więcej informacji, zobacz konstrukcja wzorca 2.6.1.

Aby określić, że sekcja kodu powinna być wykonywana w jednym wątku, niekoniecznie głównym wątku, należy zamiast tego użyć pojedynczej dyrektywy.

Przykład

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

uporządkowany

Określa, że kod w pętli równoległej for powinien być wykonywany jak sekwencyjna pętla.

#pragma omp ordered
   structured-block

Uwagi

ordered Dyrektywa musi należeć do dynamicznego zakresu obiektu lub parallel for konstrukcji z klauzulą ordered .

Dyrektywa ordered nie obsługuje żadnych klauzul.

Aby uzyskać więcej informacji, zobacz konstrukcja uporządkowana w wersji 2.6.6.

Przykład

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

Definiuje region równoległy, czyli kod, który będzie wykonywany równolegle przez wiele wątków.

#pragma omp parallel [clauses]
{
   code_block
}

Parametry

Klauzule
(Opcjonalnie) Zero lub więcej klauzul, zobacz sekcję Uwagi .

Uwagi

Dyrektywa parallel obsługuje następujące klauzule:

parallel można również używać z dyrektywami for i sekcje .

Aby uzyskać więcej informacji, zobacz konstrukcja równoległa 2.3.

Przykład

W poniższym przykładzie pokazano, jak ustawić liczbę wątków i zdefiniować region równoległy. Liczba wątków jest domyślnie równa liczbie procesorów logicznych na maszynie. Jeśli na przykład masz maszynę z jednym procesorem fizycznym, który ma włączoną funkcję hyperthreading, będzie miał dwa procesory logiczne i dwa wątki. Kolejność danych wyjściowych może się różnić na różnych maszynach.

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

sekcje

Identyfikuje sekcje kodu, które mają być podzielone między wszystkie wątki.

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

Parametry

Klauzule
(Opcjonalnie) Zero lub więcej klauzul, zobacz sekcję Uwagi .

Uwagi

Dyrektywa sections może zawierać zero lub więcej section dyrektyw.

Dyrektywa sections obsługuje następujące klauzule:

Jeśli parallel jest również określony, clauses może być dowolną klauzulą akceptowaną przez parallel dyrektywy lub sections , z wyjątkiem nowait.

Aby uzyskać więcej informacji, zobacz konstrukcję sekcji 2.4.2.

Przykład

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

Pozwala określić, że sekcja kodu powinna być wykonywana w jednym wątku, a niekoniecznie głównym wątku.

#pragma omp single [clauses]
{
   code_block
}

Parametry

Klauzule
(Opcjonalnie) Zero lub więcej klauzul, zobacz sekcję Uwagi .

Uwagi

Dyrektywa single obsługuje następujące klauzule:

Aby uzyskać więcej informacji, zobacz pojedynczą konstrukcję 2.4.3.

Aby określić, że sekcja kodu powinna być wykonywana tylko w głównym wątku, należy zamiast tego użyć dyrektywy master .

Przykład

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

Określa, że zmienna jest prywatna dla wątku.

#pragma omp threadprivate(var)

Parametry

var
Rozdzielona przecinkami lista zmiennych, które mają być prywatne dla wątku. wartość var musi być zmienną o zakresie globalnym lub przestrzeni nazw albo lokalną zmienną statyczną.

Uwagi

Dyrektywa threadprivate nie obsługuje żadnych klauzul.

Dyrektywa threadprivate jest oparta na atrybucie wątku przy użyciu słowa kluczowego __declspec; limity __declspec(thread) stosowane do threadprivate. Na przykład zmienna threadprivate będzie istnieć w każdym wątku uruchomionym w procesie, a nie tylko tych wątków, które są częścią zespołu wątków zduplikowanego przez region równoległy. Należy pamiętać o tej implementacji szczegółowo; Można zauważyć, że konstruktory typu zdefiniowanego threadprivate przez użytkownika są wywoływane częściej niż oczekiwano.

Można użyć threadprivate w dll, który jest statycznie ładowany podczas uruchamiania procesu, jednak nie można użyć threadprivate w żadnej dll, która zostanie załadowana za pośrednictwem biblioteki LoadLibrary , takich jak biblioteki DLL ładowane z /DELAYLOAD (opóźnić importowanie obciążenia), który również używa LoadLibrary.

Zmienna threadprivate typu destruktora nie ma gwarancji, że jest wywoływana jego destruktor. Na przykład:

struct MyType
{
    ~MyType();
};

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

Użytkownicy nie mają kontroli nad tym, kiedy wątki tworzące region równoległy zakończą działanie. Jeśli te wątki istnieją po zakończeniu procesu, wątki nie będą powiadamiane o zakończeniu procesu, a destruktor nie będzie wywoływany w threaded_var żadnym wątku, z wyjątkiem tego, który kończy (tutaj, wątek podstawowy). W związku z tym kod nie powinien liczyć na właściwe niszczenie threadprivate zmiennych.

Aby uzyskać więcej informacji, zobacz dyrektywę threadprivate w wersji 2.7.1.

Przykład

Aby zapoznać się z przykładem korzystania z usługi threadprivate, zobacz prywatny.