Udostępnij za pośrednictwem


Klauzule OpenMP

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

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

W przypadku atrybutów ogólnych:

Klauzula opis
jeśli Określa, czy pętla powinna być wykonywana równolegle, czy szeregowa.
num_threads Ustawia liczbę wątków w zespole wątków.
Zamówione Wymagana na równoległej instrukcji, jeśli w pętli ma być używana uporządkowana dyrektywa.
schedule Dotyczy dyrektywy for.
nowait Zastępuje barierę niejawną w dyrektywie.

W przypadku atrybutów udostępniania danych:

Klauzula opis
private Określa, że każdy wątek powinien mieć własne wystąpienie zmiennej.
firstprivate Określa, że każdy wątek powinien mieć własne wystąpienie zmiennej i że zmienna powinna być inicjowana z wartością zmiennej, ponieważ istnieje przed konstrukcją równoległą.
lastprivate Określa, że wersja otaczającego kontekstu zmiennej jest ustawiona na wersję prywatną niezależnie od tego, który wątek wykonuje ostateczną iterację (konstrukcję dla pętli) lub ostatnią sekcję (#pragma sekcjach).
Udostępnionych Określa, że co najmniej jedna zmienna powinna być współdzielona między wszystkimi wątkami.
default Określa zachowanie zmiennych niezakresowych w regionie równoległym.
reduction Określa, że co najmniej jedna zmienna prywatna dla każdego wątku jest przedmiotem operacji redukcji na końcu regionu równoległego.
copyin Umożliwia wątkom dostęp do wartości wątku głównego dla zmiennej threadprivate .
copyprivate Określa, że co najmniej jedna zmienna powinna być współdzielona między wszystkimi wątkami.

copyin

Umożliwia wątkom dostęp do wartości wątku głównego dla zmiennej threadprivate .

copyin(var)

Parametry

var
Zmienna threadprivate , która zostanie zainicjowana z wartością zmiennej w głównym wątku, tak jak istnieje przed konstrukcją równoległą.

Uwagi

copyin stosuje się do następujących dyrektyw:

Aby uzyskać więcej informacji, zobacz kopiowanie w wersji 2.7.2.7.

Przykład

Zobacz threadprivate , aby zapoznać się z przykładem użycia elementu copyin.

copyprivate

Określa, że co najmniej jedna zmienna powinna być współdzielona między wszystkimi wątkami.

copyprivate(var)

Parametry

var
Co najmniej jedna zmienna do udostępnienia. Jeśli określono więcej niż jedną zmienną, należy oddzielić nazwy zmiennych przecinkami.

Uwagi

copyprivate stosuje się do jednej dyrektywy.

Aby uzyskać więcej informacji, zobacz 2.7.2.8 copyprivate.

Przykład

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

domyślna

Określa zachowanie zmiennych niezakresowych w regionie równoległym.

default(shared | none)

Uwagi

shared, który jest w mocy, jeśli klauzula default jest nieokreślona, oznacza, że każda zmienna w regionie równoległym będzie traktowana tak, jakby została określona z klauzulą udostępnioną. noneOznacza, że wszystkie zmienne używane w regionie równoległym, które nie są objęte zakresem prywatnym, udostępnionym, redukcji, firstprivate lub klauzuli lastprivate, spowodują błąd kompilatora.

default stosuje się do następujących dyrektyw:

Aby uzyskać więcej informacji, zobacz domyślną 2.7.2.5.

Przykład

Zobacz prywatny , aby zapoznać się z przykładem użycia elementu default.

firstprivate

Określa, że każdy wątek powinien mieć własne wystąpienie zmiennej i że zmienna powinna być inicjowana z wartością zmiennej, ponieważ istnieje przed konstrukcją równoległą.

firstprivate(var)

Parametry

var
Zmienna, która ma mieć wystąpienia w każdym wątku i które zostaną zainicjowane z wartością zmiennej, ponieważ istnieje przed konstrukcją równoległą. Jeśli określono więcej niż jedną zmienną, należy oddzielić nazwy zmiennych przecinkami.

Uwagi

firstprivate stosuje się do następujących dyrektyw:

Aby uzyskać więcej informacji, zobacz 2.7.2.2 firstprivate.

Przykład

Przykład użycia elementu firstprivatemożna znaleźć w przykładzie prywatnym.

if (OpenMP)

Określa, czy pętla powinna być wykonywana równolegle, czy szeregowa.

if(expression)

Parametry

wyrażenie
Wyrażenie całkowite, które, jeśli oblicza wartość true (nonzero), powoduje równoległe wykonanie kodu w regionie równoległym. Jeśli wyrażenie daje wartość false (zero), region równoległy jest wykonywany w trybie szeregowym (przez jeden wątek).

Uwagi

if stosuje się do następujących dyrektyw:

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

Przykład

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

Określa, że wersja otaczającego kontekstu zmiennej jest ustawiona na wersję prywatną niezależnie od tego, który wątek wykonuje ostateczną iterację (konstrukcję dla pętli) lub ostatnią sekcję (#pragma sekcjach).

lastprivate(var)

Parametry

var
Zmienna, która jest ustawiona na wersję prywatną każdego wątku, wykonuje ostateczną iterację (konstrukcję for-loop) lub ostatnią sekcję (#pragma sekcji).

Uwagi

lastprivate stosuje się do następujących dyrektyw:

Aby uzyskać więcej informacji, zobacz 2.7.2.3 lastprivate.

Przykład

Zobacz harmonogram , aby zapoznać się z przykładem używania lastprivate klauzuli .

nowait

Zastępuje barierę niejawną w dyrektywie.

nowait

Uwagi

nowait stosuje się do następujących dyrektyw:

Aby uzyskać więcej informacji, zobacz konstrukcję konstrukcji 2.4.1, konstrukcję sekcji 2.4.2 i 2.4.3 pojedynczą konstrukcję.

Przykład

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

Ustawia liczbę wątków w zespole wątków.

num_threads(num)

Parametry

Num
Liczba wątków

Uwagi

Klauzula num_threads ma taką samą funkcjonalność jak funkcja omp_set_num_threads .

num_threads stosuje się do następujących dyrektyw:

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

Przykład

Zobacz równoległe , aby zapoznać się z przykładem używania num_threads klauzuli .

uporządkowany

Wymagana na równoległej instrukcji, jeśli w pętli ma być używana uporządkowana dyrektywa.

ordered

Uwagi

ordered stosuje się do dyrektywy for .

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

Przykład

Zobacz uporządkowane , aby zapoznać się z przykładem używania ordered klauzuli .

private

Określa, że każdy wątek powinien mieć własne wystąpienie zmiennej.

private(var)

Parametry

var
Zmienna, która ma mieć wystąpienia w każdym wątku.

Uwagi

private stosuje się do następujących dyrektyw:

Aby uzyskać więcej informacji, zobacz prywatną 2.7.2.1.

Przykład

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

reduction

Określa, że co najmniej jedna zmienna prywatna dla każdego wątku jest przedmiotem operacji redukcji na końcu regionu równoległego.

reduction(operation:var)

Parametry

rozdzielnicy
Operator operacji do wykonania dla zmiennej var na końcu regionu równoległego.

var
Co najmniej jedna zmienna, na której ma być zmniejszana skalarna. Jeśli określono więcej niż jedną zmienną, należy oddzielić nazwy zmiennych przecinkami.

Uwagi

reduction stosuje się do następujących dyrektyw:

Aby uzyskać więcej informacji, zobacz redukcja 2.7.2.6.

Przykład

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

harmonogram

Dotyczy dyrektywy for.

schedule(type[,size])

Parametry

type
Rodzaj planowania, dynamicalbo , guided, runtimelub static.

rozmiar
(Opcjonalnie) Określa rozmiar iteracji. rozmiar musi być liczbą całkowitą. Nieprawidłowy, gdy typ to runtime.

Uwagi

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

Przykład

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

udostępnione

Określa, że co najmniej jedna zmienna powinna być współdzielona między wszystkimi wątkami.

shared(var)

Parametry

var
Co najmniej jedna zmienna do udostępnienia. Jeśli określono więcej niż jedną zmienną, należy oddzielić nazwy zmiennych przecinkami.

Uwagi

Innym sposobem udostępniania zmiennych między wątkami jest klauzula copyprivate .

shared stosuje się do następujących dyrektyw:

Aby uzyskać więcej informacji, zobacz udostępnione 2.7.2.4.

Przykład

Zobacz prywatny , aby zapoznać się z przykładem użycia elementu shared.