Udostępnij za pośrednictwem


Odp. Przykłady

Poniżej przedstawiono przykłady konstrukcji zdefiniowanych w tym dokumencie. Instrukcja po dyrektywie jest składana tylko wtedy, gdy jest to konieczne, a instrukcja niezwiązana jest wcięta z dyrektywy poprzedzającej ją.

A.1 Prosta pętla równoległa

W poniższym przykładzie pokazano, jak zrównać pętlę przy użyciu równoległej dyrektywy . Zmienna iteracji pętli jest domyślnie prywatna, więc nie jest konieczne jawne określenie jej w klauzuli prywatnej.

#pragma omp parallel for
    for (i=1; i<n; i++)
        b[i] = (a[i] + a[i-1]) / 2.0;

Kompilacja warunkowa A.2

W poniższych przykładach pokazano użycie kompilacji warunkowej przy użyciu _OPENMP makra OpenMP. W przypadku kompilacji _OPENMP OpenMP makro staje się definiowane.

# ifdef _OPENMP
    printf_s("Compiled by an OpenMP-compliant implementation.\n");
# endif

Zdefiniowany operator preprocesora umożliwia przetestowanie więcej niż jednego makra w jednej dyrektywie.

# if defined(_OPENMP) && defined(VERBOSE)
    printf_s("Compiled by an OpenMP-compliant implementation.\n");
# endif

A.3 Regiony równoległe

Dyrektywę równoległą można używać w programach równoległych z gruboziarnistymi. W poniższym przykładzie każdy wątek w regionie równoległym decyduje o tym, na jakiej części tablicy x globalnej ma działać, na podstawie numeru wątku:

#pragma omp parallel shared(x, npoints) private(iam, np, ipoints)
{
    iam = omp_get_thread_num();
    np =  omp_get_num_threads();
    ipoints = npoints / np;
    subdomain(x, iam, ipoints);
}

A.4 Klauzula nowait

Jeśli w regionie równoległym istnieje wiele pętli niezależnych, możesz użyć klauzuli nowait , aby uniknąć domniemanej bariery na końcu for dyrektywy w następujący sposób:

#pragma omp parallel
{
    #pragma omp for nowait
        for (i=1; i<n; i++)
             b[i] = (a[i] + a[i-1]) / 2.0;
    #pragma omp for nowait
        for (i=0; i<m; i++)
            y[i] = sqrt(z[i]);
}

A.5 Dyrektywa krytyczna

Poniższy przykład zawiera kilka dyrektyw krytycznych . W przykładzie pokazano model kolejkowania, w którym zadanie jest odsyłane i pracowało. Aby chronić przed wieloma wątkami w kolejce tego samego zadania, operacja usuwania z kolejki musi znajdować się w critical sekcji. Ponieważ dwie kolejki w tym przykładzie są niezależne, są chronione przez critical dyrektywy o różnych nazwach, xaxis i yaxis.

#pragma omp parallel shared(x, y) private(x_next, y_next)
{
    #pragma omp critical ( xaxis )
        x_next = dequeue(x);
    work(x_next);
    #pragma omp critical ( yaxis )
        y_next = dequeue(y);
    work(y_next);
}

A.6 Klauzula lastprivate

Poprawne wykonanie czasami zależy od wartości, którą ostatnia iteracja pętli przypisuje do zmiennej. Takie programy muszą zawierać listę wszystkich takich zmiennych jak argumenty do klauzuli lastprivate , tak aby wartości zmiennych są takie same jak w przypadku wykonywania pętli sekwencyjnie.

#pragma omp parallel
{
   #pragma omp for lastprivate(i)
      for (i=0; i<n-1; i++)
         a[i] = b[i] + b[i+1];
}
a[i]=b[i];

W poprzednim przykładzie wartość i na końcu regionu równoległego będzie równa n-1, jak w przypadku przypadku sekwencyjnym.

A.7 Klauzula redukcji

W poniższym przykładzie przedstawiono klauzulę redukcji :

#pragma omp parallel for private(i) shared(x, y, n) \
                         reduction(+: a, b)
    for (i=0; i<n; i++) {
        a = a + x[i];
        b = b + y[i];
    }

Sekcje równoległe A.8

W poniższym przykładzie (w sekcji 2.4.2) funkcje xaxis, yaxis i zaxis mogą być wykonywane współbieżnie. Pierwsza section dyrektywa jest opcjonalna. Wszystkie section dyrektywy muszą znajdować się w zakresie parallel sections leksykalnym konstrukcji.

#pragma omp parallel sections
{
    #pragma omp section
        xaxis();
    #pragma omp section
        yaxis();
    #pragma omp section
        zaxis();
}

A.9 Dyrektywy pojedyncze

W poniższym przykładzie pokazano pojedynczą dyrektywę. W tym przykładzie tylko jeden wątek (zazwyczaj pierwszy wątek, który napotyka single dyrektywę) wyświetla komunikat postępu. Użytkownik nie może podjąć żadnych założeń dotyczących tego, który wątek wykona sekcję single . Wszystkie inne wątki pominą sekcję single i zatrzymają się na barierze single na końcu konstrukcji. Jeśli inne wątki mogą kontynuować bez oczekiwania na wątek wykonujący single sekcję, klauzulę nowait można określić w single dyrektywie.

#pragma omp parallel
{
    #pragma omp single
        printf_s("Beginning work1.\n");
    work1();
    #pragma omp single
        printf_s("Finishing work1.\n");
    #pragma omp single nowait
        printf_s("Finished work1 and beginning work2.\n");
    work2();
}

A.10 Kolejność sekwencyjne

Uporządkowane sekcje są przydatne w przypadku sekwencyjnego porządkowania danych wyjściowych z pracy wykonywanej równolegle. Następujący program wyświetla indeksy w kolejności sekwencyjnej:

#pragma omp for ordered schedule(dynamic)
    for (i=lb; i<ub; i+=st)
        work(i);
void work(int k)
{
    #pragma omp ordered
        printf_s(" %d", k);
}

A.11 Stała liczba wątków

Niektóre programy polegają na stałej, określonej liczbie wątków do poprawnego wykonania. Ponieważ domyślne ustawienie dynamicznej korekty liczby wątków jest definiowane przez implementację, takie programy mogą wyłączyć funkcję wątków dynamicznych i jawnie ustawić liczbę wątków, aby zachować przenośność. W poniższym przykładzie pokazano, jak to zrobić przy użyciu omp_set_dynamic i omp_set_num_threads:

omp_set_dynamic(0);
omp_set_num_threads(16);
#pragma omp parallel shared(x, npoints) private(iam, ipoints)
{
    if (omp_get_num_threads() != 16)
      abort();
    iam = omp_get_thread_num();
    ipoints = npoints/16;
    do_by_16(x, iam, ipoints);
}

W tym przykładzie program wykonuje poprawnie tylko wtedy, gdy jest wykonywany przez 16 wątków. Jeśli implementacja nie może obsługiwać 16 wątków, zachowanie tego przykładu jest zdefiniowane przez implementację.

Liczba wątków wykonujących region równoległy pozostaje stała w regionie równoległym, niezależnie od ustawienia wątków dynamicznych. Mechanizm wątków dynamicznych określa liczbę wątków do użycia na początku regionu równoległego i utrzymuje ją na stałe przez czas trwania regionu.

A.12 Dyrektywa niepodzielna

Poniższy przykład pozwala uniknąć warunków wyścigu (jednoczesne aktualizacje elementu x przez wiele wątków) przy użyciu dyrektywy niepodzielnej :

#pragma omp parallel for shared(x, y, index, n)
    for (i=0; i<n; i++)
    {
        #pragma omp atomic
            x[index[i]] += work1(i);
        y[i] += work2(i);
    }

Zaletą zastosowania atomic dyrektywy w tym przykładzie jest to, że umożliwia ona równoległe aktualizowanie dwóch różnych elementów x. Jeśli zamiast tego jest używana dyrektywa krytyczna, wszystkie aktualizacje elementów x są wykonywane szeregowo (choć nie w żadnej gwarantowanej kolejności).

Dyrektywa atomic ma zastosowanie tylko do instrukcji C lub C++ bezpośrednio po niej. W związku z tym elementy y nie są aktualizowane niepodziealnie w tym przykładzie.

A.13 Dyrektywa flush z listą

W poniższym przykładzie użyto flush dyrektywy do synchronizacji określonych obiektów między parami wątków między punktami:

int   sync[NUMBER_OF_THREADS];
float work[NUMBER_OF_THREADS];
#pragma omp parallel private(iam,neighbor) shared(work,sync)
{
    iam = omp_get_thread_num();
    sync[iam] = 0;
    #pragma omp barrier

    // Do computation into my portion of work array
    work[iam] = ...;

    //  Announce that I am done with my work
    // The first flush ensures that my work is
    // made visible before sync.
    // The second flush ensures that sync is made visible.
    #pragma omp flush(work)
    sync[iam] = 1;
    #pragma omp flush(sync)

    // Wait for neighbor
    neighbor = (iam>0 ? iam : omp_get_num_threads()) - 1;
    while (sync[neighbor]==0)
    {
        #pragma omp flush(sync)
    }

    // Read neighbor's values of work array
    ... = work[neighbor];
}

A.14 Dyrektywa flush bez listy

Poniższy przykład (w sekcji 2.6.5) rozróżnia obiekty udostępnione, których dotyczy dyrektywa bez listy z obiektów flush udostępnionych, których nie dotyczy problem:

// omp_flush_without_list.c
#include <omp.h>

int x, *p = &x;

void f1(int *q)
{
    *q = 1;
    #pragma omp flush
    // x, p, and *q are flushed
    //   because they are shared and accessible
    // q is not flushed because it is not shared.
}

void f2(int *q)
{
    #pragma omp barrier
    *q = 2;

    #pragma omp barrier
    // a barrier implies a flush
    // x, p, and *q are flushed
    //   because they are shared and accessible
    // q is not flushed because it is not shared.
}

int g(int n)
{
    int i = 1, j, sum = 0;
    *p = 1;

    #pragma omp parallel reduction(+: sum) num_threads(10)
    {
        f1(&j);
        // i, n and sum were not flushed
        //   because they were not accessible in f1
        // j was flushed because it was accessible
        sum += j;
        f2(&j);
        // i, n, and sum were not flushed
        //   because they were not accessible in f2
        // j was flushed because it was accessible
        sum += i + j + *p + n;
    }
    return sum;
}

int main()
{
}

A.15 Liczba użytych wątków

Rozważmy następujący nieprawidłowy przykład (w sekcji 3.1.2):

np = omp_get_num_threads(); // misplaced
#pragma omp parallel for schedule(static)
    for (i=0; i<np; i++)
        work(i);

Wywołanie omp_get_num_threads() zwraca wartość 1 w sekcji szeregowej kodu, więc parametr np zawsze będzie równy 1 w poprzednim przykładzie. Aby określić liczbę wątków, które zostaną wdrożone dla regionu równoległego, wywołanie powinno znajdować się wewnątrz regionu równoległego.

W poniższym przykładzie pokazano, jak ponownie napisać ten program bez uwzględniania zapytania dotyczącego liczby wątków:

#pragma omp parallel private(i)
{
    i = omp_get_thread_num();
    work(i);
}

Blokady A.16

W poniższym przykładzie (w sekcji 3.2) argument funkcji blokady powinien mieć typ omp_lock_ti że nie trzeba go opróżniać. Funkcje blokady powodują, że wątki będą bezczynne podczas oczekiwania na wpis do pierwszej sekcji krytycznej, ale w celu wykonania innych czynności podczas oczekiwania na wpis do drugiego. Funkcja omp_set_lock blokuje, ale omp_test_lock funkcja nie umożliwia wykonania pracy skip() .

// omp_using_locks.c
// compile with: /openmp /c
#include <stdio.h>
#include <omp.h>

void work(int);
void skip(int);

int main() {
   omp_lock_t lck;
   int id;

   omp_init_lock(&lck);
   #pragma omp parallel shared(lck) private(id)
   {
      id = omp_get_thread_num();

      omp_set_lock(&lck);
      printf_s("My thread id is %d.\n", id);

      // only one thread at a time can execute this printf
      omp_unset_lock(&lck);

      while (! omp_test_lock(&lck)) {
         skip(id);   // we do not yet have the lock,
                     // so we must do something else
      }
      work(id);     // we now have the lock
                    // and can do the work
      omp_unset_lock(&lck);
   }
   omp_destroy_lock(&lck);
}

A.17 Zagnieżdżone blokady

W poniższym przykładzie (w sekcji 3.2) pokazano, jak można użyć blokady zagnieżdżonej do synchronizowania aktualizacji zarówno z całą strukturą, jak i z jednym z jego elementów członkowskich.

#include <omp.h>
typedef struct {int a,b; omp_nest_lock_t lck;} pair;

void incr_a(pair *p, int a)
{
    // Called only from incr_pair, no need to lock.
    p->a += a;
}

void incr_b(pair *p, int b)
{
    // Called both from incr_pair and elsewhere,
    // so need a nestable lock.

    omp_set_nest_lock(&p->lck);
    p->b += b;
    omp_unset_nest_lock(&p->lck);
}

void incr_pair(pair *p, int a, int b)
{
    omp_set_nest_lock(&p->lck);
    incr_a(p, a);
    incr_b(p, b);
    omp_unset_nest_lock(&p->lck);
}

void f(pair *p)
{
    extern int work1(), work2(), work3();
    #pragma omp parallel sections
    {
        #pragma omp section
            incr_pair(p, work1(), work2());
        #pragma omp section
            incr_b(p, work3());
    }
}

A.18 Zagnieżdżone dla dyrektyw

Poniższy przykład for zagnieżdżania dyrektywy jest zgodny, ponieważ wewnętrzne i zewnętrzne for dyrektywy wiążą się z różnymi regionami równoległymi:

#pragma omp parallel default(shared)
{
    #pragma omp for
        for (i=0; i<n; i++)
        {
            #pragma omp parallel shared(i, n)
            {
                #pragma omp for
                    for (j=0; j<n; j++)
                        work(i, j);
            }
        }
}

Zgodna jest również następująca odmiana powyższego przykładu:

#pragma omp parallel default(shared)
{
    #pragma omp for
        for (i=0; i<n; i++)
            work1(i, n);
}

void work1(int i, int n)
{
    int j;
    #pragma omp parallel default(shared)
    {
        #pragma omp for
            for (j=0; j<n; j++)
                work2(i, j);
    }
    return;
}

A.19 Przykłady przedstawiające niepoprawne zagnieżdżanie dyrektyw udostępniania pracy

Przykłady w tej sekcji ilustrują reguły zagnieżdżania dyrektywy.

Poniższy przykład jest niezgodny, ponieważ dyrektywy wewnętrzne i zewnętrzne for są zagnieżdżone i powiązane z tą samą parallel dyrektywą:

void wrong1(int n)
{
  #pragma omp parallel default(shared)
  {
      int i, j;
      #pragma omp for
      for (i=0; i<n; i++) {
          #pragma omp for
              for (j=0; j<n; j++)
                 work(i, j);
     }
   }
}

Następująca dynamicznie zagnieżdżona wersja poprzedniego przykładu jest również niezgodna:

void wrong2(int n)
{
  #pragma omp parallel default(shared)
  {
    int i;
    #pragma omp for
      for (i=0; i<n; i++)
        work1(i, n);
  }
}

void work1(int i, int n)
{
  int j;
  #pragma omp for
    for (j=0; j<n; j++)
      work2(i, j);
}

Poniższy przykład jest niezgodny, ponieważ for dyrektywy i single są zagnieżdżone i wiążą się z tym samym regionem równoległym:

void wrong3(int n)
{
  #pragma omp parallel default(shared)
  {
    int i;
    #pragma omp for
      for (i=0; i<n; i++) {
        #pragma omp single
          work(i);
      }
  }
}

Poniższy przykład jest niezgodny, ponieważ barrier dyrektywa wewnątrz elementu for może spowodować zakleszczenie:

void wrong4(int n)
{
  #pragma omp parallel default(shared)
  {
    int i;
    #pragma omp for
      for (i=0; i<n; i++) {
        work1(i);
        #pragma omp barrier
        work2(i);
      }
  }
}

Poniższy przykład jest niezgodny, ponieważ barrier wyniki zakleszczenia wynika z faktu, że tylko jeden wątek naraz może wprowadzić sekcję krytyczną:

void wrong5()
{
  #pragma omp parallel
  {
    #pragma omp critical
    {
       work1();
       #pragma omp barrier
       work2();
    }
  }
}

Poniższy przykład jest niezgodny, ponieważ barrier wyniki zakleszczenia wynika z faktu, że tylko jeden wątek wykonuje sekcję single :

void wrong6()
{
  #pragma omp parallel
  {
    setup();
    #pragma omp single
    {
      work1();
      #pragma omp barrier
      work2();
    }
    finish();
  }
}

A.20 Dyrektywy bariery wiązania

Reguły powiązania dyrektywy wzywają dyrektywę do powiązania z najbliższą dyrektywą barrier otaczającą parallel . Aby uzyskać więcej informacji na temat powiązania dyrektywy, zobacz sekcję 2.8.

W poniższym przykładzie wywołanie z głównego do pod2 jest zgodne, ponieważ barrier element (w pod3) wiąże się z regionem równoległym w pod2. Wywołanie z głównej do pod1 jest zgodne, ponieważ barrier powiązanie z regionem równoległym w podroutynie sub2. Wywołanie z głównego do sub3 jest zgodne, ponieważ barrier nie wiąże się z żadnym regionem równoległym i jest ignorowane. barrier Ponadto jedyna synchronizacja zespołu wątków w otaczającym regionie równoległym, a nie wszystkich wątków utworzonych w sub1.

int main()
{
    sub1(2);
    sub2(2);
    sub3(2);
}

void sub1(int n)
{
    int i;
    #pragma omp parallel private(i) shared(n)
    {
        #pragma omp for
        for (i=0; i<n; i++)
            sub2(i);
    }
}

void sub2(int k)
{
     #pragma omp parallel shared(k)
     sub3(k);
}

void sub3(int n)
{
    work(n);
    #pragma omp barrier
    work(n);
}

Zmienne zakresu A.21 z klauzulą prywatną

Wartości i i j w poniższym przykładzie są niezdefiniowane po wyjściu z regionu równoległego:

int i, j;
i = 1;
j = 2;
#pragma omp parallel private(i) firstprivate(j)
{
  i = 3;
  j = j + 2;
}
printf_s("%d %d\n", i, j);

Aby uzyskać więcej informacji na temat klauzuli private , zobacz sekcję 2.7.2.1.

A.22 Klauzula default(none)

W poniższym przykładzie odróżnić zmienne, których dotyczy klauzula default(none) , od zmiennych, które nie są:

// openmp_using_clausedefault.c
// compile with: /openmp
#include <stdio.h>
#include <omp.h>

int x, y, z[1000];
#pragma omp threadprivate(x)

void fun(int a) {
   const int c = 1;
   int i = 0;

   #pragma omp parallel default(none) private(a) shared(z)
   {
      int j = omp_get_num_thread();
             //O.K.  - j is declared within parallel region
      a = z[j];       // O.K.  - a is listed in private clause
                      //      - z is listed in shared clause
      x = c;          // O.K.  - x is threadprivate
                      //      - c has const-qualified type
      z[i] = y;       // C3052 error - cannot reference i or y here

      #pragma omp for firstprivate(y)
         for (i=0; i<10 ; i++) {
            z[i] = y;  // O.K. - i is the loop control variable
                       // - y is listed in firstprivate clause
          }
       z[i] = y;   // Error - cannot reference i or y here
   }
}

Aby uzyskać więcej informacji na temat klauzuli, zobacz sekcję default 2.7.2.5.

A.23 Przykłady uporządkowanej dyrektywy

Istnieje możliwość posiadania wielu uporządkowanych sekcji z określoną klauzulą for ordered . Pierwszy przykład jest niezgodny, ponieważ interfejs API określa następującą regułę:

"Iteracja pętli z konstrukcją for nie może wykonywać tej samej ordered dyrektywy więcej niż raz i nie może wykonywać więcej niż jednej ordered dyrektywy". (Zobacz sekcję 2.6.6).)

W tym niezgodnym przykładzie wszystkie iteracji wykonują dwie uporządkowane sekcje:

#pragma omp for ordered
for (i=0; i<n; i++)
{
    ...
    #pragma omp ordered
    { ... }
    ...
    #pragma omp ordered
    { ... }
    ...
}

Poniższy zgodny przykład przedstawia sekcję z więcej niż jedną uporządkowaną sekcją for :

#pragma omp for ordered
for (i=0; i<n; i++)
{
    ...
    if (i <= 10)
    {
        ...
        #pragma omp ordered
        { ... }
    }
    ...
    (i > 10)
    {
        ...
        #pragma omp ordered
        { ... }
    }
    ...
}

A.24 Przykład klauzuli prywatnej

Klauzula prywatna regionu równoległego jest obowiązują tylko w zakresie leksykalnym regionu, a nie dla dynamicznego zakresu regionu. W związku z tym w poniższym przykładzie każde użycie zmiennej a w for pętli w procedurze f odnosi się do prywatnej kopii elementu , a użycie w rutynowej g odnosi się do globalnego elementu .

int a;

void f(int n)
{
    a = 0;

    #pragma omp parallel for private(a)
    for (int i=1; i<n; i++)
    {
        a = i;
        g(i, n);
        d(a);     // Private copy of "a"
        ...
    }
    ...

void g(int k, int n)
{
    h(k,a); // The global "a", not the private "a" in f
}

A.25 Przykłady klauzuli atrybutu copyprivate danych

Przykład 1: Klauzula copyprivate może służyć do emisji wartości uzyskanych przez pojedynczy wątek bezpośrednio do wszystkich wystąpień zmiennych prywatnych w innych wątkach.

float x, y;
#pragma omp threadprivate(x, y)

void init( )
{
    float a;
    float b;

    #pragma omp single copyprivate(a,b,x,y)
    {
        get_values(a,b,x,y);
    }

    use_values(a, b, x, y);
}

Jeśli rutynowy inicjowanie jest wywoływane z regionu szeregowego, jego zachowanie nie ma wpływu na obecność dyrektyw. Po wykonaniu wywołania procedury get_values przez jeden wątek żaden wątek nie pozostawia konstrukcji, dopóki prywatne obiekty wyznaczone przez a, b, x i y we wszystkich wątkach nie staną się zdefiniowane przy użyciu odczytanych wartości.

Przykład 2: W przeciwieństwie do poprzedniego przykładu załóżmy, że odczyt musi być wykonywany przez określony wątek, powiedzmy wątek główny. W takim przypadku klauzula copyprivate nie może służyć do bezpośredniego wykonywania emisji, ale może służyć do zapewnienia dostępu do tymczasowego obiektu udostępnionego.

float read_next( )
{
    float * tmp;
    float return_val;

    #pragma omp single copyprivate(tmp)
    {
        tmp = (float *) malloc(sizeof(float));
    }

    #pragma omp master
    {
        get_float( tmp );
    }

    #pragma omp barrier
    return_val = *tmp;
    #pragma omp barrier

    #pragma omp single
    {
       free(tmp);
    }

    return return_val;
}

Przykład 3: Załóżmy, że przed wprowadzeniem nie można łatwo określić liczby obiektów blokad wymaganych w regionie równoległym. Klauzulę copyprivate można użyć do zapewnienia dostępu do udostępnionych obiektów blokady przydzielonych w tym regionie równoległym.

#include <omp.h>

omp_lock_t *new_lock()
{
    omp_lock_t *lock_ptr;

    #pragma omp single copyprivate(lock_ptr)
    {
        lock_ptr = (omp_lock_t *) malloc(sizeof(omp_lock_t));
        omp_init_lock( lock_ptr );
    }

    return lock_ptr;
}

A.26 Dyrektywa threadprivate

W poniższych przykładach pokazano, jak używać dyrektywy threadprivate w celu nadania każdemu wątkowi oddzielnego licznika.

Przykład 1

int counter = 0;
#pragma omp threadprivate(counter)

int sub()
{
    counter++;
    return(counter);
}

Przykład 2

int sub()
{
    static int counter = 0;
    #pragma omp threadprivate(counter)
    counter++;
    return(counter);
}

Tablice o zmiennej długości A.27 C99

W poniższym przykładzie pokazano, jak używać tablic długości zmiennej C99 (VLA) w dyrektywie firstprivate .

Uwaga

Tablice o zmiennej długości nie są obecnie obsługiwane w języku Visual C++.

void f(int m, int C[m][m])
{
    double v1[m];
    ...
    #pragma omp parallel firstprivate(C, v1)
    ...
}

A.28 Klauzula num_threads

W poniższym przykładzie przedstawiono klauzulę num_threads . Region równoległy jest wykonywany z maksymalnie 10 wątkami.

#include <omp.h>
main()
{
    omp_set_dynamic(1);
    ...
    #pragma omp parallel num_threads(10)
    {
        ... parallel region ...
    }
}

A.29 Konstrukcje udostępniania pracy wewnątrz konstrukcji krytycznej

W poniższym przykładzie pokazano użycie konstrukcji udostępniania pracy wewnątrz critical konstrukcji. Ten przykład jest zgodny, ponieważ konstrukcja udostępniania pracy i critical konstrukcja nie są powiązane z tym samym regionem równoległym.

void f()
{
  int i = 1;
  #pragma omp parallel sections
  {
    #pragma omp section
    {
      #pragma omp critical (name)
      {
        #pragma omp parallel
        {
          #pragma omp single
          {
            i++;
          }
        }
      }
    }
  }
}

A.30 Reprivatization

W poniższym przykładzie pokazano reprivatizację zmiennych. Zmienne prywatne można oznaczyć private ponownie w zagnieżdżonej dyrektywie. Nie musisz udostępniać tych zmiennych w otaczającym regionie równoległym.

int i, a;
...
#pragma omp parallel private(a)
{
  ...
  #pragma omp parallel for private(a)
  for (i=0; i<10; i++)
     {
       ...
     }
}

Funkcje blokady bezpieczne wątkowo A.31

W poniższym przykładzie języka C++ pokazano, jak zainicjować tablicę blokad w regionie równoległym przy użyciu omp_init_lock.

// A_13_omp_init_lock.cpp
// compile with: /openmp
#include <omp.h>

omp_lock_t *new_locks() {
   int i;
   omp_lock_t *lock = new omp_lock_t[1000];
   #pragma omp parallel for private(i)
   for (i = 0 ; i < 1000 ; i++)
      omp_init_lock(&lock[i]);

   return lock;
}

int main () {}