Sdílet prostřednictvím


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 by mělo mít 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 nadřazeného kontextu proměnné je nastavená na privátní verzi vlákna, která spouští konečnou iteraci (konstruktor for-loop) nebo poslední oddíl (#pragma oddíly).
společný 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.
reduction 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

Příklad použití copyinnajdete v tématu threadprivate .

copyprivate

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

default

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í firstprivatenajdete v příkladu v privátním souboru.

if (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ý je vyhodnocen jako true (nenulový), způsobí paralelní spuštění kódu v paralelní oblasti. 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 nadřazeného kontextu proměnné je nastavená na privátní verzi vlákna, která spouští konečnou iteraci (konstruktor for-loop) nebo poslední oddíl (#pragma oddíly).

lastprivate(var)

Parametry

var
Proměnná, která je nastavená na privátní verzi vlákna, spustí konečnou iteraci (konstruktor for-loop) nebo poslední oddíl (#pragma oddíly).

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 příkladu klauzule using 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 konstruktor, 2.4.2 oddíly konstrukce a 2.4.3 jeden konstruktor.

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

num_threads

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

Příklad klauzule using num_threads najdete paralelně.

ordered

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 účely .

Další informace naleznete v tématu 2.4.1 pro konstruktor.

Příklad

Podívejte se na seřazený příklad klauzule using ordered .

private

Určuje, že každé vlákno by mělo mít 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)

reduction

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 operace, který má provádět s proměnnými 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 ve verzi 2.7.2.6.

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

type
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 runtimetyp .

Poznámky

Další informace naleznete v tématu 2.4.1 pro konstruktor.

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

shared

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.