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_t
i ż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 () {}