Sdílet prostřednictvím


Direktivy jazyka OpenMP

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

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

Pro paralelní sdílení práce:

Direktiva Popis
parallel Definuje paralelní oblast, což je kód, který bude spuštěný několika vlákny paralelně.
for Způsobí rozdělení práce ve for smyčce uvnitř paralelní oblasti mezi vlákna.
sekce Identifikuje oddíly kódu, které se mají rozdělit mezi všechna vlákna.
single Umožňuje určit, že část kódu by měla být spuštěna v jednom vlákně, ne nutně hlavní vlákno.

Pro hlavní vlákno a synchronizaci:

Direktiva Popis
master Určuje, že část programu by měla spouštět pouze hlavní vlákno.
critical Určuje, že se kód spouští pouze na jednom vlákně najednou.
barrier Synchronizuje všechna vlákna v týmu; všechna vlákna se pozastaví na bariérě, dokud všechna vlákna nespustí bariéru.
atomic Určuje, že umístění paměti, které se bude aktualizovat atomicky.
spláchnout Určuje, že všechna vlákna mají stejné zobrazení paměti pro všechny sdílené objekty.
objednaný Určuje, že kód pod paralelizovanou for smyčkou by se měl spustit jako sekvenční smyčka.

Pro datové prostředí:

Direktiva Popis
threadprivate Určuje, že proměnná je pro vlákno soukromá.

atomic

Určuje, že umístění paměti, které se bude aktualizovat atomicky.

#pragma omp atomic
   expression

Parametry

výraz
Příkaz, který má lvalue, jehož umístění paměti chcete chránit před více než jedním zápisem.

Poznámky

Direktiva atomic nepodporuje žádné klauzule.

Další informace naleznete v článku 2.6.4 atomic konstruktor.

Příklad

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

Synchronizuje všechna vlákna v týmu; všechna vlákna se pozastaví na bariérě, dokud všechna vlákna nespustí bariéru.

#pragma omp barrier

Poznámky

Direktiva barrier nepodporuje žádné klauzule.

Další informace naleznete v tématu 2.6.3 bariérová direktiva.

Příklad

Ukázku použití barriernajdete v hlavní části.

critical

Určuje, že se kód spouští pouze na jednom vlákně najednou.

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

Parametry

Jméno
(Volitelné) Název pro identifikaci kritického kódu. Název musí být uzavřený v závorkách.

Poznámky

Direktiva critical nepodporuje žádné klauzule.

Další informace naleznete v tématu 2.6.2 kritický konstruktor.

Příklad

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

Určuje, že všechna vlákna mají stejné zobrazení paměti pro všechny sdílené objekty.

#pragma omp flush [(var)]

Parametry

var
(Volitelné) Seznam proměnných oddělených čárkami, které představují objekty, které chcete synchronizovat. Pokud není zadána hodnota var , vyprázdní se veškerá paměť.

Poznámky

Direktiva flush nepodporuje žádné klauzule.

Další informace naleznete v tématu 2.6.5 flush direktiva.

Příklad

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

pro

Způsobí rozdělení práce ve for smyčce uvnitř paralelní oblasti mezi vlákna.

#pragma omp [parallel] for [clauses]
   for_statement

Parametry

klauzule
(Volitelné) Nulové nebo více klauzulí najdete v části Poznámky .

for_statement
Smyčka for . Nedefinované chování způsobí, že kód uživatele ve for smyčce změní proměnnou indexu.

Poznámky

Direktiva for podporuje následující klauzule:

Je-li parallel rovněž zadán, clauses může být libovolná klauzule přijatá parallel direktivou nebo for direktivou s výjimkou nowait.

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

Příklad

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

Určuje, že část programu by měla spouštět pouze hlavní vlákno.

#pragma omp master
{
   code_block
}

Poznámky

Direktiva master nepodporuje žádné klauzule.

Další informace naleznete v tématu 2.6.1 hlavní konstruktor.

Chcete-li určit, že část kódu by měla být provedena v jednom vlákně, ne nutně hlavní vlákno, použijte místo toho jedinou direktivu.

Příklad

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

Určuje, že kód pod paralelizovanou for smyčkou by se měl spustit jako sekvenční smyčka.

#pragma omp ordered
   structured-block

Poznámky

Direktiva ordered musí být v dynamickém rozsahu objektu for nebo parallel for konstruktoru s klauzulí ordered .

Direktiva ordered nepodporuje žádné klauzule.

Další informace naleznete v tématu 2.6.6 uspořádaný konstruktor.

Příklad

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

Definuje paralelní oblast, což je kód, který bude spuštěný několika vlákny paralelně.

#pragma omp parallel [clauses]
{
   code_block
}

Parametry

klauzule
(Volitelné) Nulové nebo více klauzulí najdete v části Poznámky .

Poznámky

Direktiva parallel podporuje následující klauzule:

parallel lze také použít s direktivami for a sections .

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

Příklad

Následující ukázka ukazuje, jak nastavit počet vláken a definovat paralelní oblast. Počet vláken se ve výchozím nastavení rovná počtu logických procesorů v počítači. Pokud máte například počítač s jedním fyzickým procesorem, který má povolenou hyperthreading, bude mít dva logické procesory a dvě vlákna. Pořadí výstupu se může lišit na různých počítačích.

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

Identifikuje oddíly kódu, které se mají rozdělit mezi všechna vlákna.

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

Parametry

klauzule
(Volitelné) Nulové nebo více klauzulí najdete v části Poznámky .

Poznámky

Direktiva sections může obsahovat nulové nebo více section direktiv.

Direktiva sections podporuje následující klauzule:

Je-li parallel rovněž zadán, clauses může být libovolná klauzule přijatá parallel direktivou nebo sections direktivou s výjimkou nowait.

Další informace naleznete v části 2.4.2 oddíly konstrukce.

Příklad

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

Umožňuje určit, že část kódu by měla být spuštěna v jednom vlákně, ne nutně hlavní vlákno.

#pragma omp single [clauses]
{
   code_block
}

Parametry

klauzule
(Volitelné) Nulové nebo více klauzulí najdete v části Poznámky .

Poznámky

Direktiva single podporuje následující klauzule:

Další informace naleznete v tématu 2.4.3 jeden konstruktor.

Chcete-li určit, že část kódu by měla být provedena pouze v hlavním vlákně, použijte místo toho hlavní direktivu.

Příklad

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

Určuje, že proměnná je pro vlákno soukromá.

#pragma omp threadprivate(var)

Parametry

var
Seznam proměnných oddělených čárkami, které chcete v vlákně nastavit jako soukromé. var musí být buď globální proměnná nebo proměnná s oborem názvů, nebo místní statická proměnná.

Poznámky

Direktiva threadprivate nepodporuje žádné klauzule.

Direktiva threadprivate je založena na atributu vlákna pomocí klíčového slova __declspec ; omezení platí pro __declspec(thread) threadprivate. Proměnná threadprivate například bude existovat v libovolném vlákně, které se spustilo v procesu, a ne pouze ve vláknech, která jsou součástí týmu vlákna, který vytvořila paralelní oblast. Mějte na paměti podrobnosti o této implementaci; Můžete si všimnout, že konstruktory pro threadprivate uživatelem definovaný typ se volají častěji, než se očekává.

Můžete použít threadprivate v knihovně DLL, která je staticky načtena při spuštění procesu, ale nelze použít threadprivate v žádné knihovně DLL, která bude načtena prostřednictvím LoadLibrary , jako jsou knihovny DLL načtené s /DELAYLOAD (odložený import načítání), které také používá LoadLibrary.

Proměnná threadprivate destrukovatelného typu není zaručená, že má její destruktor volaný. Příklad:

struct MyType
{
    ~MyType();
};

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

Uživatelé nemají žádnou kontrolu nad tím, kdy se vlákna tvořící paralelní oblast ukončí. Pokud tato vlákna existují při ukončení procesu, vlákna nebudou upozorněna na ukončení procesu a destruktor nebude volán v threaded_var žádném vlákně s výjimkou vlákna, která se ukončí (tady primární vlákno). Kód by tedy neměl počítat se správným zničením proměnných threadprivate .

Další informace naleznete v tématu 2.7.1 threadprivate direktiva.

Příklad

Ukázku použití threadprivatenajdete v části Soukromé.