OpenMP – klauzule

Poskytuje odkazy na klauzule používané v rozhraní OpenMP API.

Visual C++ podporuje následující klauzule OpenMP.

Obecné atributy:

Klauzule Popis
když Určuje, zda má být smyčka spuštěna paralelně nebo sériově.
num_threads Nastaví počet vláken v týmu vláken.
objednaný Vyžaduje se paralelně pro příkaz, pokud se má ve smyčce použít uspořádaná direktiva.
schedule Platí pro směrnici for .
nowait Přepíše bariéru implicitní v direktivě.

Atributy sdílení dat:

Klauzule Popis
private Určuje, že každé vlákno má mít svou vlastní instanci proměnné.
firstprivate Určuje, že každé vlákno by mělo mít vlastní instanci proměnné a že proměnná by měla být inicializována s hodnotou proměnné, protože existuje před paralelním konstruktorem.
lastprivate Určuje, že verze proměnné v nadřazeném kontextu je nastavena na privátní verzi vlákna, které provede poslední iteraci (konstrukce for-cyklus) nebo poslední sekci (#pragma sekce).
sdílený Určuje, že jedna nebo více proměnných by se měla sdílet mezi všemi vlákny.
default Určuje chování neskopovaných proměnných v paralelní oblasti.
redukce Určuje, že jedna nebo více proměnných, které jsou soukromé pro každé vlákno, jsou předmětem operace redukce na konci paralelní oblasti.
copyin Umožňuje vlákenm přístup k hodnotě hlavního vlákna pro proměnnou threadprivate .
copyprivate Určuje, že jedna nebo více proměnných by se měla sdílet mezi všemi vlákny.

copyin

Umožňuje vlákenm přístup k hodnotě hlavního vlákna pro proměnnou threadprivate .

copyin(var)

Parametry

var
Proměnná threadprivate , která bude inicializována hodnotou proměnné v hlavním vlákně, protože existuje před paralelním konstruktorem.

Poznámky

copyin se vztahuje na následující direktivy:

Další informace naleznete v části 2.7.2.7 copyin.

Příklad

Viz threadprivate pro příklad použití copyin.

kopírovat soukromě

Určuje, že jedna nebo více proměnných by se měla sdílet mezi všemi vlákny.

copyprivate(var)

Parametry

var
Jednu nebo více proměnných, které chcete sdílet. Pokud je zadáno více než jedna proměnná, oddělte názvy proměnných čárkou.

Poznámky

copyprivatese vztahuje na jedinou směrnici.

Další informace najdete v tématu 2.7.2.8 copyprivate.

Příklad

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

výchozí

Určuje chování neskopovaných proměnných v paralelní oblasti.

default(shared | none)

Poznámky

shared, která je platná, pokud default je klauzule nezadaná, znamená, že jakákoli proměnná v paralelní oblasti bude považována za zadanou se sdílenou klauzulí. noneznamená, že všechny proměnné použité v paralelní oblasti, které nejsou vymezeny oborem privátní, sdílené, redukce, firstprivate nebo lastprivate klauzule, způsobí chybu kompilátoru.

default se vztahuje na následující direktivy:

Další informace najdete ve výchozím nastavení 2.7.2.5.

Příklad

Podívejte se na soukromou ukázku použití default.

firstprivate

Určuje, že každé vlákno by mělo mít vlastní instanci proměnné a že proměnná by měla být inicializována s hodnotou proměnné, protože existuje před paralelním konstruktorem.

firstprivate(var)

Parametry

var
Proměnná, která má mít instance v každém vlákně a která se inicializuje s hodnotou proměnné, protože existuje před paralelním konstruktorem. Pokud je zadáno více než jedna proměnná, oddělte názvy proměnných čárkou.

Poznámky

firstprivate se vztahuje na následující direktivy:

Další informace naleznete v tématu 2.7.2.2 firstprivate.

Příklad

Příklad použití firstprivate najdete v příkladu soukromého souboru.

pokud (OpenMP)

Určuje, zda má být smyčka spuštěna paralelně nebo sériově.

if(expression)

Parametry

výraz
Integrální výraz, který, pokud je vyhodnocen jako pravda (nenulový), způsobí, že se kód v paralelní oblasti spustí paralelně. Pokud se výraz vyhodnotí jako false (nula), provede se paralelní oblast sériově (jedním vláknem).

Poznámky

if se vztahuje na následující direktivy:

Další informace naleznete v části 2.3 paralelní konstrukce.

Příklad

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

Určuje, že verze proměnné v nadřazeném kontextu je nastavena na privátní verzi vlákna, které provede poslední iteraci (konstrukce for-cyklus) nebo poslední sekci (#pragma sekce).

lastprivate(var)

Parametry

var
Proměnná, která je nastavena jako privátní verze toho vlákna, které provede závěrečnou iteraci (konstrukce for-loop) nebo poslední sekci (#pragma sekce).

Poznámky

lastprivate se vztahuje na následující direktivy:

Další informace najdete v tématu 2.7.2.3 lastprivate.

Příklad

Podívejte se na plán pro příklad použití klauzule lastprivate.

nowait

Přepíše bariéru implicitní v direktivě.

nowait

Poznámky

nowait se vztahuje na následující direktivy:

Další informace naleznete v tématu 2.4.1 pro konstrukci, 2.4.2 konstrukce sekcí a 2.4.3 jediná konstrukce.

Příklad

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

počet_vláken

Nastaví počet vláken v týmu vláken.

num_threads(num)

Parametry

Num
Počet vláken

Poznámky

Klauzule num_threads má stejné funkce jako funkce omp_set_num_threads .

num_threads se vztahuje na následující direktivy:

Další informace naleznete v části 2.3 paralelní konstrukce.

Příklad

Podívejte se na parallel pro příklad použití num_threads klauzule.

objednáno

Vyžaduje se paralelně pro příkaz, pokud se má ve smyčce použít uspořádaná direktiva.

ordered

Poznámky

ordered se vztahuje na směrnici pro.

Další informace naleznete pod 2.4.1 pro konstrukci.

Příklad

Podívejte se na příklad použití klauzule seřazenéordered.

soukromý

Určuje, že každé vlákno má mít svou vlastní instanci proměnné.

private(var)

Parametry

var
Proměnná, která má mít instance v každém vlákně.

Poznámky

private se vztahuje na následující direktivy:

Další informace naleznete v části 2.7.2.1 private.

Příklad

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

snížení

Určuje, že jedna nebo více proměnných, které jsou soukromé pro každé vlákno, jsou předmětem operace redukce na konci paralelní oblasti.

reduction(operation:var)

Parametry

operace
Operátor pro operaci, která se má provést na proměnných var na konci paralelní oblasti.

var
Jedna nebo více proměnných, u kterých se má provést skalární redukce. Pokud je zadáno více než jedna proměnná, oddělte názvy proměnných čárkou.

Poznámky

reduction se vztahuje na následující direktivy:

Další informace naleznete v části 2.7.2.6 reduction.

Příklad

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

plán

Platí pro směrnici for .

schedule(type[,size])

Parametry

typ
Druh plánování, buď dynamic, guided, runtimenebo static.

velikost
(Volitelné) Určuje velikost iterací. velikost musí být celé číslo. Není platný, pokud je typruntime.

Poznámky

Další informace naleznete pod 2.4.1 pro konstrukci.

Příklad

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

sdílený

Určuje, že jedna nebo více proměnných by se měla sdílet mezi všemi vlákny.

shared(var)

Parametry

var
Jednu nebo více proměnných, které chcete sdílet. Pokud je zadáno více než jedna proměnná, oddělte názvy proměnných čárkou.

Poznámky

Dalším způsobem sdílení proměnných mezi vlákny je klauzule copyprivate .

shared se vztahuje na následující direktivy:

Další informace najdete ve sdílené verzi 2.7.2.4.

Příklad

Podívejte se na soukromou ukázku použití shared.