2. Dyrektywy
Dyrektywy są oparte na #pragma
dyrektywach zdefiniowanych w standardach C i C++. Kompilatory obsługujące interfejs API OpenMP C i C++ będą zawierać opcję wiersza polecenia, która aktywuje i umożliwia interpretację wszystkich dyrektyw kompilatora OpenMP.
2.1 Format dyrektywy
Składnia dyrektywy OpenMP jest formalnie określona przez gramatykę w dodatku C i nieformalnie w następujący sposób:
#pragma omp directive-name [clause[ [,] clause]...] new-line
Każda dyrektywa zaczyna się od #pragma omp
, aby zmniejszyć potencjalny konflikt z innymi (rozszerzeniami innych niż OpenMP lub rozszerzenia dostawcy do openMP) dyrektywy pragma o tych samych nazwach. Pozostała część dyrektywy jest zgodna z konwencjami standardów języka C i C++ dla dyrektyw kompilatora. W szczególności białe znaki mogą być używane przed i po #
, a czasami białe znaki muszą być używane do oddzielania wyrazów w dyrektywie. Przetwarzanie wstępne tokenów po elemencie #pragma omp
podlega zamianie makr.
W dyrektywach jest rozróżniana wielkość liter. Kolejność, w jakiej klauzule pojawiają się w dyrektywach, nie jest znacząca. Klauzule dotyczące dyrektyw mogą być powtarzane zgodnie z potrzebami, z zastrzeżeniem ograniczeń wymienionych w opisie każdej klauzuli. Jeśli lista-zmiennych jest wyświetlana w klauzuli, musi określać tylko zmienne. Na dyrektywę można określić tylko jedną nazwę dyrektywy. Na przykład następująca dyrektywa nie jest dozwolona:
/* ERROR - multiple directive names not allowed */
#pragma omp parallel barrier
Dyrektywa OpenMP ma zastosowanie do co najwyżej jednej pomyślnej instrukcji, która musi być blokiem ustrukturyzowanym.
2.2 Kompilacja warunkowa
Nazwa _OPENMP
makra jest definiowana przez implementacje zgodne z protokołem OpenMP jako stałej dziesiętnej rrrr, która będzie rokiem i miesiącem zatwierdzonej specyfikacji. To makro nie może być przedmiotem #define
dyrektywy lub przetwarzania #undef
wstępnego.
#ifdef _OPENMP
iam = omp_get_thread_num() + index;
#endif
Jeśli dostawcy definiują rozszerzenia openMP, mogą określić dodatkowe wstępnie zdefiniowane makra.
Konstrukcja równoległa 2.3
Poniższa dyrektywa definiuje region równoległy, który jest regionem programu, który ma być wykonywany równolegle przez wiele wątków. Ta dyrektywa jest podstawową konstrukcją, która rozpoczyna wykonywanie równoległe.
#pragma omp parallel [clause[ [, ]clause] ...] new-line structured-block
Klauzula jest jedną z następujących opcji:
if(
wyrażenie-skalarne)
private(
lista zmiennych)
firstprivate(
lista zmiennych)
default(shared | none)
shared(
lista zmiennych)
copyin(
lista zmiennych)
reduction(
operator:
lista zmiennych)
num_threads(
wyrażenie-liczba całkowita)
Po przejściu wątku do konstrukcji równoległej zostanie utworzony zespół wątków, jeśli spełniony jest jeden z następujących przypadków:
- Żadna klauzula nie
if
jest obecna. - Wyrażenie
if
oblicza wartość niezerową.
Ten wątek staje się głównym wątkiem zespołu, z numerem wątku 0, a wszystkie wątki w zespole, w tym wątek główny, wykonują region równolegle. Jeśli wartość if
wyrażenia wynosi zero, region jest serializowany.
Aby określić liczbę żądanych wątków, następujące reguły będą brane pod uwagę w podanej kolejności. Pierwsza reguła, której warunek zostanie spełniony, zostanie zastosowana:
Jeśli klauzula
num_threads
jest obecna, wartość wyrażenia całkowitego jest liczbą żądanych wątków.omp_set_num_threads
Jeśli funkcja biblioteki została wywołana, wartość argumentu w ostatnio wykonanym wywołaniu jest liczbą żądanych wątków.Jeśli zmienna środowiskowa
OMP_NUM_THREADS
jest zdefiniowana, wartość tej zmiennej środowiskowej jest liczbą żądanych wątków.Jeśli żadna z powyższych metod nie jest używana, zdefiniowana jest liczba żądanych wątków.
Jeśli klauzula num_threads
jest obecna, zastępuje liczbę wątków żądanych przez omp_set_num_threads
funkcję biblioteki lub OMP_NUM_THREADS
zmienną środowiskową tylko dla regionu równoległego, do którego jest stosowany. Nie ma to wpływu na późniejsze regiony równoległe.
Liczba wątków wykonywanych w regionie równoległym zależy również od tego, czy włączono dynamiczną korektę liczby wątków. Jeśli korekta dynamiczna jest wyłączona, żądana liczba wątków wykona region równoległy. Jeśli włączono korektę dynamiczną, żądana liczba wątków to maksymalna liczba wątków, które mogą wykonywać region równoległy.
Jeśli wystąpi region równoległy, gdy dynamiczne dostosowanie liczby wątków jest wyłączone, a liczba wątków żądanych dla regionu równoległego jest większa niż liczba, którą może dostarczyć system czasu wykonywania, zachowanie programu jest definiowane przez implementację. Implementacja może na przykład przerwać wykonywanie programu lub serializować region równoległy.
Funkcja omp_set_dynamic
biblioteki i zmienna OMP_DYNAMIC
środowiskowa mogą służyć do włączania i wyłączania dynamicznego dostosowywania liczby wątków.
Liczba procesorów fizycznych hostująca wątki w danym momencie jest zdefiniowana przez implementację. Po utworzeniu liczba wątków w zespole pozostaje stała na czas trwania tego regionu równoległego. Można go jawnie zmienić przez użytkownika lub automatycznie przez system czasu wykonywania z jednego regionu równoległego do innego.
Instrukcje zawarte w dynamicznym zakresie regionu równoległego są wykonywane przez każdy wątek, a każdy wątek może wykonywać ścieżkę instrukcji, które różnią się od innych wątków. Dyrektywy napotkane poza zakresem leksykalnym regionu równoległego są określane jako dyrektywy oddzielone.
Na końcu regionu równoległego znajduje się domniemana bariera. Tylko główny wątek zespołu kontynuuje wykonywanie na końcu regionu równoległego.
Jeśli wątek w zespole wykonującym region równoległy napotka inną konstrukcję równoległą, tworzy nowy zespół i staje się wzorcem tego nowego zespołu. Zagnieżdżone regiony równoległe są domyślnie serializowane. W związku z tym domyślnie zagnieżdżony region równoległy jest wykonywany przez zespół składający się z jednego wątku. Domyślne zachowanie może zostać zmienione przy użyciu funkcji omp_set_nested
biblioteki środowiska uruchomieniowego lub zmiennej środowiskowej OMP_NESTED
. Jednak liczba wątków w zespole wykonującym zagnieżdżony region równoległy jest definiowana przez implementację.
parallel
Ograniczenia dyrektywy są następujące:
Co najwyżej jedna
if
klauzula może pojawić się w dyrektywie.Nie określono, czy występują jakiekolwiek skutki uboczne wewnątrz wyrażenia if lub
num_threads
wyrażenia.throw
Wykonanie wewnątrz regionu równoległego musi spowodować wznowienie wykonywania w dynamicznym zakresie tego samego bloku strukturalnego i musi zostać przechwycone przez ten sam wątek, który zgłosił wyjątek.Tylko jedna
num_threads
klauzula może pojawić się w dyrektywie. Wyrażenienum_threads
jest obliczane poza kontekstem regionu równoległego i musi zostać obliczone na dodatnią wartość całkowitą.Kolejność oceny
if
klauzul inum_threads
jest nieokreślona.
Odwołania krzyżowe
private
, ,firstprivate
,shared
default
,copyin
, ireduction
klauzule (sekcja 2.7.2)- zmienna środowiskowa OMP_NUM_THREADS
- funkcja biblioteki omp_set_dynamic
- zmienna środowiskowa OMP_DYNAMIC
- omp_set_nested, funkcja
- zmienna środowiskowa OMP_NESTED
- funkcja biblioteki omp_set_num_threads
2.4 Konstrukcje udostępniania pracy
Konstrukcja udostępniania pracy dystrybuuje wykonywanie skojarzonej instrukcji wśród członków zespołu, którzy go napotykają. Dyrektywy udostępniania pracy nie uruchamiają nowych wątków i nie ma domniemanej bariery wejścia do konstrukcji udostępniania pracy.
Sekwencja konstrukcji i barrier
dyrektyw udostępniania pracy musi być taka sama dla każdego wątku w zespole.
Protokół OpenMP definiuje następujące konstrukcje udostępniania pracy, a te konstrukcje zostały opisane w poniższych sekcjach:
- dla dyrektywy
- dyrektywa w sekcjach
- pojedyncza dyrektywa
2.4.1 dla konstrukcji
Dyrektywa for
identyfikuje iteracyjną konstrukcję udostępniania pracy, która określa, że iteracje skojarzonej pętli będą wykonywane równolegle. Iteracji for
pętli są dystrybuowane między wątkami, które już istnieją w zespole wykonującym konstrukcję równoległą, z którą jest powiązana. Składnia for
konstrukcji jest następująca:
#pragma omp for [clause[[,] clause] ... ] new-line for-loop
Klauzula jest jedną z następujących opcji:
private(
lista zmiennych)
firstprivate(
lista zmiennych)
lastprivate(
lista zmiennych)
reduction(
operator:
lista zmiennych)
ordered
schedule(
kind [,
chunk_size])
nowait
Dyrektywa for
nakłada ograniczenia dotyczące struktury odpowiedniej for
pętli. W szczególności odpowiednia for
pętla musi mieć kształt kanoniczny:
for (
wyrażenie init-expr ;
var logical-op b ;
wyrażenie incr )
wyrażenie init-expr
Jedna z następujących:
- var = lb
- liczba całkowita typu var = lb
wyrażenie incr
Jedna z następujących:
++
Var- Var
++
--
Var- Var
--
- var
+=
incr - var
-=
incr - var var
+
=
incr - var incr var
=
+
- var var
-
=
incr
var
Podpisana zmienna całkowita. Jeśli ta zmienna byłaby w przeciwnym razie udostępniana, niejawnie jest ona prywatna przez czas trwania for
. Nie należy modyfikować tej zmiennej w treści instrukcji for
. O ile zmienna nie zostanie określona, jej wartość po pętli jest nieokreślona lastprivate
.
logiczna op
Jedna z następujących:
<
<=
>
>=
lb, b i incr
Niezmienne wyrażenia liczb całkowitych pętli. Nie ma synchronizacji podczas obliczania tych wyrażeń, więc wszystkie oceniane efekty uboczne generują nieokreślone wyniki.
Formularz kanoniczny umożliwia obliczanie liczby iteracji pętli na wejściu do pętli. To obliczenie jest wykonywane z wartościami typu var po promocji całkowitych. W szczególności, jeśli wartość b -
lb +
incr nie może być reprezentowana w tym typie, wynik jest nieokreślony. Ponadto, jeśli wartość logical-op ma <
wartość lub <=
, wyrażenie incr-expr musi spowodować zwiększenie wartości var dla każdej iteracji pętli. Jeśli wyrażenie logiczne ma wartość >
lub >=
, wyrażenie incr-expr musi spowodować , że var będzie mniejszy w każdej iteracji pętli.
Klauzula schedule
określa sposób dzielenia iteracji for
pętli między wątki zespołu. Poprawność programu nie może zależeć od tego, który wątek wykonuje określoną iterację. Wartość chunk_size, jeśli została określona, musi być niezmiennym wyrażeniem liczby całkowitej pętli z wartością dodatnią. Nie ma synchronizacji podczas obliczania tego wyrażenia, więc wszystkie oceniane efekty uboczne generują nieokreślone wyniki. Rodzaj harmonogramu może być jedną z następujących wartości:
Tabela 2–1: schedule
wartości rodzaju klauzuli
Wartość | Opis |
---|---|
static | Po schedule(static, określeniu chunk_size ) iteracji są podzielone na fragmenty rozmiaru określonego przez chunk_size. Fragmenty są statycznie przypisywane do wątków w zespole w sposób okrężny w kolejności numeru wątku. Jeśli nie określono chunk_size , przestrzeń iteracji jest podzielona na fragmenty, które są w przybliżeniu równe rozmiarze, z jednym fragmentem przypisanym do każdego wątku. |
dynamiczna | Po schedule(dynamic, określeniu chunk_size ) iteracji są podzielone na serię fragmentów, z których każda zawiera iterację chunk_size . Każdy fragment jest przypisywany do wątku, który oczekuje na przypisanie. Wątek wykonuje fragment iteracji, a następnie czeka na następne przypisanie, dopóki nie zostaną przypisane żadne fragmenty. Ostatni fragment do przypisania może mieć mniejszą liczbę iteracji. Jeśli nie określono chunk_size , wartość domyślna to 1. |
Kierować | Po schedule(guided, określeniu chunk_size ) iteracji są przypisywane do wątków we fragmentach o mniejszych rozmiarach. Gdy wątek zakończy przypisaną część iteracji, zostanie dynamicznie przypisany kolejny fragment, dopóki żaden nie zostanie pozostawiony. W przypadku chunk_size 1 rozmiar każdego fragmentu jest w przybliżeniu liczbą nieprzypisanych iteracji podzielonych przez liczbę wątków. Rozmiary te zmniejszają się prawie wykładniczo do 1. W przypadku chunk_size o wartości k większej niż 1 rozmiary zmniejszają się prawie wykładniczo do k, z tą różnicą, że ostatni fragment może mieć mniej niż k iteracji. Jeśli nie określono chunk_size , wartość domyślna to 1. |
środowisko uruchomieniowe | Gdy schedule(runtime) zostanie określony, decyzja dotycząca planowania zostanie odroczona do czasu wykonania. Typ harmonogramu i rozmiar fragmentów można wybrać w czasie wykonywania, ustawiając zmienną środowiskową OMP_SCHEDULE . Jeśli ta zmienna środowiskowa nie jest ustawiona, wynikowy harmonogram jest zdefiniowany przez implementację. Po schedule(runtime) określeniu chunk_size nie można określić. |
W przypadku braku jawnie zdefiniowanej schedule
klauzuli domyślna schedule
jest zdefiniowana przez implementację.
Program zgodny z protokołem OpenMP nie powinien polegać na określonym harmonogramie prawidłowego wykonywania. Program nie powinien polegać na rodzaju harmonogramu, który jest dokładnie zgodny z opisem podanym powyżej, ponieważ istnieje możliwość zmiany implementacji tego samego rodzaju harmonogramu w różnych kompilatorach. Opisy mogą służyć do wybierania harmonogramu odpowiedniego dla określonej sytuacji.
Klauzula ordered
musi być obecna, gdy ordered
dyrektywy wiążą się z konstrukcją for
.
Na końcu for
konstrukcji znajduje się niejawna bariera, chyba że określono klauzulę nowait
.
for
Ograniczenia dyrektywy są następujące:
Pętla
for
musi być blokiem ustrukturyzowanym, a ponadto jej wykonanie nie może zostać zakończone przez instrukcjębreak
.Wartości wyrażeń sterujących
for
pętli skojarzonej z dyrektywąfor
muszą być takie same dla wszystkich wątków w zespole.Zmienna
for
iteracji pętli musi mieć podpisany typ liczby całkowitej.Tylko jedna
schedule
klauzulafor
może pojawić się w dyrektywie.Tylko jedna
ordered
klauzulafor
może pojawić się w dyrektywie.Tylko jedna
nowait
klauzulafor
może pojawić się w dyrektywie.Nie jest określony, czy lub jak często występują jakiekolwiek skutki uboczne w chunk_size, lb, b lub wyrażeń incr .
Wartość wyrażenia chunk_size musi być taka sama dla wszystkich wątków w zespole.
Odwołania krzyżowe
private
, ,firstprivate
lastprivate
ireduction
klauzule (sekcja 2.7.2)- OMP_SCHEDULE zmiennej środowiskowej
- uporządkowana konstrukcja
- schedule , klauzula
Konstrukcja sekcji 2.4.2
Dyrektywa sections
identyfikuje nieteracyjną konstrukcję udostępniania pracy, która określa zestaw konstrukcji, które mają być podzielone między wątki w zespole. Każda sekcja jest wykonywana raz przez wątek w zespole. Składnia sections
dyrektywy jest następująca:
#pragma omp sections [clause[[,] clause] ...] new-line
{
[#pragma omp section new-line]
structured-block
[#pragma omp section new-linestructured-block ]
...
}
Klauzula jest jedną z następujących opcji:
private(
lista zmiennych)
firstprivate(
lista zmiennych)
lastprivate(
lista zmiennych)
reduction(
operator:
lista zmiennych)
nowait
Każda sekcja jest poprzedzona dyrektywą section
, chociaż section
dyrektywa jest opcjonalna dla pierwszej sekcji. Dyrektywy section
muszą znajdować się w zakresie sections
leksykalnym dyrektywy. Na końcu sections
konstrukcji znajduje się niejawna bariera, chyba że określono element nowait
.
sections
Ograniczenia dyrektywy są następujące:
section
Dyrektywa nie może znajdować się poza zakresemsections
leksykalnym dyrektywy.Tylko jedna
nowait
klauzulasections
może pojawić się w dyrektywie.
Odwołania krzyżowe
private
, ,firstprivate
lastprivate
ireduction
klauzule (sekcja 2.7.2)
2.4.3 pojedyncza konstrukcja
Dyrektywa single
identyfikuje konstrukcję określającą, że skojarzony blok ustrukturyzowany jest wykonywany tylko przez jeden wątek w zespole (niekoniecznie główny wątek). Składnia single
dyrektywy jest następująca:
#pragma omp single [clause[[,] clause] ...] new-linestructured-block
Klauzula jest jedną z następujących opcji:
private(
lista zmiennych)
firstprivate(
lista zmiennych)
copyprivate(
lista zmiennych)
nowait
Istnieje niejawna bariera po single
konstrukcji, chyba że określono klauzulę nowait
.
single
Ograniczenia dyrektywy są następujące:
- Tylko jedna
nowait
klauzulasingle
może pojawić się w dyrektywie. - Klauzula
copyprivate
nie może być używana z klauzuląnowait
.
Odwołania krzyżowe
private
,firstprivate
icopyprivate
klauzule (sekcja 2.7.2)
2.5 Połączone równoległe konstrukcje współdzielenia pracy
Połączone konstrukcje współużytkowania równoległego to skróty do określania regionu równoległego, który ma tylko jedną konstrukcję udostępniania pracy. Semantyka tych dyrektyw jest taka sama jak jawne określenie parallel
dyrektywy, po której następuje pojedyncza konstrukcja udostępniania pracy.
W poniższych sekcjach opisano połączone równoległe konstrukcje udostępniania pracy:
- równoległe dla dyrektywy
- parallel sections , dyrektywa
2.5.1 równoległe do konstrukcji
Dyrektywa parallel for
jest skrótem parallel
dla regionu, który zawiera tylko jedną for
dyrektywę. Składnia parallel for
dyrektywy jest następująca:
#pragma omp parallel for [clause[[,] clause] ...] new-linefor-loop
Niniejsza dyrektywa zezwala na wszystkie klauzule parallel
dyrektywy i for
dyrektywę, z wyjątkiem nowait
klauzuli, z identycznymi znaczeniami i ograniczeniami. Semantyka jest taka sama jak jawne określenie parallel
dyrektywy, po for
której następuje dyrektywa.
Odwołania krzyżowe
- równoległa dyrektywa
- dla dyrektywy
- Klauzule atrybutu danych
Konstrukcja równoległych sekcji 2.5.2
Dyrektywa parallel sections
zawiera formularz skrótu do określania parallel
regionu, który ma tylko jedną sections
dyrektywę. Semantyka jest taka sama jak jawne określenie parallel
dyrektywy, po sections
której następuje dyrektywa. Składnia parallel sections
dyrektywy jest następująca:
#pragma omp parallel sections [clause[[,] clause] ...] new-line
{
[#pragma omp section new-line]
structured-block
[#pragma omp section new-linestructured-block ]
...
}
Klauzula może być jedną z klauzul zaakceptowanych przez parallel
dyrektywy isections
, z wyjątkiem klauzuli nowait
.
Odwołania krzyżowe
- równoległa dyrektywa
- dyrektywa w sekcjach
2.6 Dyrektywy wzorca i synchronizacji
W poniższych sekcjach opisano:
- konstrukcja wzorca
- konstrukcja krytyczna
- dyrektywa barierowa
- konstrukcja niepodzielna
- flush , dyrektywa
- uporządkowana konstrukcja
Konstrukcja wzorca 2.6.1
Dyrektywa master
identyfikuje konstrukcję określającą ustrukturyzowany blok wykonywany przez główny wątek zespołu. Składnia master
dyrektywy jest następująca:
#pragma omp master new-linestructured-block
Inne wątki w zespole nie wykonują skojarzonego bloku strukturalnego. Nie ma domniemanej bariery zarówno na wejściu, jak i wyjściu z konstrukcji głównej.
Konstrukcja krytyczna 2.6.2
Dyrektywa critical
identyfikuje konstrukcję, która jednocześnie ogranicza wykonywanie skojarzonego bloku strukturalnego do pojedynczego wątku. Składnia critical
dyrektywy jest następująca:
#pragma omp critical [(name)] new-linestructured-block
Opcjonalna nazwa może służyć do identyfikowania regionu krytycznego. Identyfikatory używane do identyfikowania regionu krytycznego mają połączenie zewnętrzne i znajdują się w przestrzeni nazw, która jest oddzielona od przestrzeni nazw używanych przez etykiety, tagi, elementy członkowskie i zwykłe identyfikatory.
Wątek czeka na początku regionu krytycznego, dopóki żaden inny wątek nie wykonuje krytycznego regionu (w dowolnym miejscu w programie) o tej samej nazwie. Wszystkie nienazwane dyrektywy są mapowane critical
na tę samą nieokreśloną nazwę.
2.6.3 dyrektywa barierowa
Dyrektywa barrier
synchronizuje wszystkie wątki w zespole. Po napotkaniu każdy wątek w zespole czeka, aż wszystkie pozostałe osoby osiągną ten punkt. Składnia barrier
dyrektywy jest następująca:
#pragma omp barrier new-line
Po tym, jak wszystkie wątki w zespole napotkały barierę, każdy wątek w zespole rozpoczyna wykonywanie instrukcji po dyrektywie bariery równolegle. barrier
Ponieważ dyrektywa nie ma instrukcji języka C w ramach jego składni, istnieją pewne ograniczenia dotyczące umieszczania w programie. Aby uzyskać więcej informacji na temat formalnej gramatyki, zobacz dodatek C. Poniższy przykład ilustruje te ograniczenia.
/* ERROR - The barrier directive cannot be the immediate
* substatement of an if statement
*/
if (x!=0)
#pragma omp barrier
...
/* OK - The barrier directive is enclosed in a
* compound statement.
*/
if (x!=0) {
#pragma omp barrier
}
Konstrukcja niepodzielna 2.6.4
Dyrektywa atomic
zapewnia, że określona lokalizacja pamięci jest aktualizowana niepodziealnie, zamiast narażać ją na możliwość wielu równoczesnych wątków zapisu. Składnia atomic
dyrektywy jest następująca:
#pragma omp atomic new-lineexpression-stmt
Instrukcja wyrażenia musi mieć jedną z następujących form:
- x wyrażenie binop
=
- x
++
++
x- x
--
--
x
W poprzednich wyrażeniach:
x to wyrażenie lvalue z typem skalarnym.
wyrażenie jest wyrażeniem o typie skalarnym i nie odwołuje się do obiektu wyznaczonego przez x.
binop nie jest przeciążonym operatorem i jest jednym z
+
,*
,-
,^
&
|
/
<<
lub .>>
Chociaż implementacja jest zdefiniowana, czy implementacja zastępuje wszystkie atomic
dyrektywy dyrektywami critical
o tej samej unikatowej nazwie, atomic
dyrektywa pozwala na lepszą optymalizację. Często dostępne są instrukcje sprzętowe, które mogą wykonywać niepodzielne aktualizacje z najmniejszym obciążeniem.
Tylko obciążenie i przechowywanie obiektu wyznaczonego przez x są niepodzielne; ocena wyrażenia nie jest niepodzielna. Aby uniknąć warunków wyścigu, wszystkie aktualizacje lokalizacji równolegle powinny być chronione dyrektywą atomic
, z wyjątkiem tych, które są znane jako wolne od warunków wyścigu.
atomic
Ograniczenia dyrektywy są następujące:
- Wszystkie odwołania niepodzielne do lokalizacji przechowywania x w całym programie muszą mieć zgodny typ.
Przykłady
extern float a[], *p = a, b;
/* Protect against races among multiple updates. */
#pragma omp atomic
a[index[i]] += b;
/* Protect against races with updates through a. */
#pragma omp atomic
p[i] -= 1.0f;
extern union {int n; float x;} u;
/* ERROR - References through incompatible types. */
#pragma omp atomic
u.n++;
#pragma omp atomic
u.x -= 1.0f;
2.6.5 dyrektywa opróżniania
Dyrektywa flush
, niezależnie od tego, czy jest jawna, czy dorozumiana, określa punkt sekwencji "międzywątkowy", w którym implementacja jest wymagana, aby zapewnić, że wszystkie wątki w zespole mają spójny widok niektórych obiektów (określonych poniżej) w pamięci. Oznacza to, że poprzednie oceny wyrażeń odwołujących się do tych obiektów zostały ukończone, a kolejne oceny nie zostały jeszcze rozpoczęte. Na przykład kompilatory muszą przywrócić wartości obiektów z rejestrów do pamięci, a sprzęt może wymagać opróżnienia zapisu do pamięci i ponownego załadowania wartości obiektów z pamięci.
Składnia flush
dyrektywy jest następująca:
#pragma omp flush [(variable-list)] new-line
Jeśli obiekty wymagające synchronizacji mogą być wyznaczone przez zmienne, te zmienne można określić na opcjonalnej liście zmiennych. Jeśli wskaźnik znajduje się na liście zmiennych, sam wskaźnik jest opróżniany, a nie obiekt, do których odwołuje się wskaźnik.
flush
Dyrektywa bez listy zmiennych synchronizuje wszystkie obiekty udostępnione z wyjątkiem obiektów niedostępnych z automatycznym czasem przechowywania. (Prawdopodobnie będzie to miało większe obciążenie niż flush
na liście zmiennych). flush
Dyrektywa bez listy zmiennych jest dorozumiana dla następujących dyrektyw:
barrier
- Przy wejściu do i wyjściu z
critical
- Przy wejściu do i wyjściu z
ordered
- Przy wejściu do i wyjściu z
parallel
- Przy wyjściu z
for
- Przy wyjściu z
sections
- Przy wyjściu z
single
- Przy wejściu do i wyjściu z
parallel for
- Przy wejściu do i wyjściu z
parallel sections
Dyrektywa nie jest dorozumiana, jeśli klauzula nowait
jest obecna. Należy zauważyć, że flush
dyrektywa nie jest dorozumiana dla żadnego z następujących elementów:
- Przy wejściu do
for
- Przy wejściu do lub wyjściu z
master
- Przy wejściu do
sections
- Przy wejściu do
single
Odwołanie, które uzyskuje dostęp do wartości obiektu z nietrwałym typem kwalifikowanym zachowuje się tak, jakby istniała flush
dyrektywa określająca ten obiekt w poprzednim punkcie sekwencji. Odwołanie, które modyfikuje wartość obiektu z typem kwalifikowanym zmiennotrwałym zachowuje się tak, jakby istniała flush
dyrektywa określająca ten obiekt w kolejnym punkcie sekwencji.
flush
Ponieważ dyrektywa nie ma instrukcji języka C w ramach jego składni, istnieją pewne ograniczenia dotyczące umieszczania w programie. Aby uzyskać więcej informacji na temat formalnej gramatyki, zobacz dodatek C. Poniższy przykład ilustruje te ograniczenia.
/* ERROR - The flush directive cannot be the immediate
* substatement of an if statement.
*/
if (x!=0)
#pragma omp flush (x)
...
/* OK - The flush directive is enclosed in a
* compound statement
*/
if (x!=0) {
#pragma omp flush (x)
}
flush
Ograniczenia dyrektywy są następujące:
- Zmienna określona
flush
w dyrektywie nie może mieć typu odwołania.
Konstrukcja uporządkowana 2.6.6
Blok ustrukturyzowany po ordered
dyrektywie jest wykonywany w kolejności wykonywania iteracji w pętli sekwencyjnej. Składnia ordered
dyrektywy jest następująca:
#pragma omp ordered new-linestructured-block
ordered
Dyrektywa musi należeć do dynamicznego for
zakresu konstrukcji lubparallel for
. for
Dyrektywa orparallel for
, do której ordered
wiązania konstrukcji musi mieć klauzulę określoną zgodnie z opisem ordered
w sekcji 2.4.1. W wykonaniu for
konstrukcji lub parallel for
z klauzulą ordered
ordered
konstrukcje są wykonywane ściśle w kolejności, w której będą wykonywane w sekwencyjnym wykonaniu pętli.
ordered
Ograniczenia dyrektywy są następujące:
- Iteracja pętli z konstrukcją
for
nie może wykonywać tej samej uporządkowanej dyrektywy więcej niż raz i nie może wykonywać więcej niż jednejordered
dyrektywy.
2.7 Środowisko danych
W tej sekcji przedstawiono dyrektywę i kilka klauzul do kontrolowania środowiska danych podczas wykonywania regionów równoległych w następujący sposób:
Dyrektywa threadprivate jest udostępniana w celu tworzenia zmiennych zakresu plików, zakresu przestrzeni nazw lub statycznych zmiennych zakresu bloków w wątku.
Klauzule, które mogą być określone w dyrektywach w celu kontrolowania atrybutów udostępniania zmiennych na czas trwania konstrukcji równoległych lub współużytkowania pracy, opisano w sekcji 2.7.2.
2.7.1, dyrektywa threadprivate
Dyrektywa threadprivate
sprawia, że nazwany zakres plików, zakres przestrzeni nazw lub statyczne zmienne zakresu bloków określone w zmiennej-liście prywatnej do wątku. lista-zmiennych to rozdzielona przecinkami lista zmiennych, które nie mają niekompletnego typu. Składnia threadprivate
dyrektywy jest następująca:
#pragma omp threadprivate(variable-list) new-line
Każda kopia zmiennej threadprivate
jest inicjowana raz, w nieokreślonym punkcie w programie przed pierwszym odwołaniem do tej kopii i w zwykły sposób (tj. jako kopia główna zostanie zainicjowana w serii wykonywania programu). Należy pamiętać, że jeśli obiekt jest przywoływany w jawnym inicjatorze threadprivate
zmiennej, a wartość obiektu jest modyfikowana przed pierwszym odwołaniem do kopii zmiennej, zachowanie nie jest określone.
Podobnie jak w przypadku każdej zmiennej prywatnej, wątek nie może odwoływać się do kopii obiektu innego wątku threadprivate
. Podczas regionów seryjnych i głównych regionów programu odwołania będą do kopii obiektu głównego wątku.
Po wykonaniu pierwszego regionu równoległego dane w threadprivate
obiektach mają gwarancję trwałości tylko wtedy, gdy mechanizm wątków dynamicznych został wyłączony, a liczba wątków pozostaje niezmieniona dla wszystkich regionów równoległych.
Ograniczenia threadprivate
dyrektywy są następujące:
threadprivate
Dyrektywa dotycząca zmiennych zakresu plików lub zakresu przestrzeni nazw musi znajdować się poza dowolną definicją lub deklaracją i musi poprzedzać wszystkie odwołania do dowolnych zmiennych na liście.Każda zmienna na liście
threadprivate
zmiennych dyrektywy w zakresie pliku lub przestrzeni nazw musi odwoływać się do deklaracji zmiennej w zakresie pliku lub przestrzeni nazw, który leksykalnie poprzedza dyrektywę.threadprivate
Dyrektywa statycznych zmiennych zakresu blokowego musi być wyświetlana w zakresie zmiennej, a nie w zagnieżdżonym zakresie. Dyrektywa musi poprzedzać leksykalnie wszystkie odwołania do dowolnej ze zmiennych na liście.Każda zmienna na liście
threadprivate
zmiennych dyrektywy w zakresie bloku musi odwoływać się do deklaracji zmiennej w tym samym zakresie, który leksykalnie poprzedza dyrektywę. Deklaracja zmiennej musi używać specyfikatora klasy magazynu statycznego.Jeśli zmienna jest określona w
threadprivate
dyrektywie w jednej jednostce tłumaczenia, musi być określona wthreadprivate
dyrektywie w każdej jednostce tłumaczenia, w której jest zadeklarowana.Zmienna nie może być wyświetlana
threadprivate
w żadnej klauzuli z wyjątkiemcopyin
klauzuli ,copyprivate
,schedule
,num_threads
lub klauzuliif
.Adres zmiennej
threadprivate
nie jest stałą adresu.Zmienna
threadprivate
nie może mieć niekompletnego typu ani typu odwołania.Zmienna
threadprivate
o typie innej niż POD musi mieć dostępny, jednoznaczny konstruktor kopiowania, jeśli jest zadeklarowany za pomocą jawnego inicjatora.
W poniższym przykładzie pokazano, jak modyfikowanie zmiennej wyświetlanej w inicjatorze może spowodować nieokreślone zachowanie, a także jak uniknąć tego problemu przy użyciu obiektu pomocniczego i konstruktora kopii.
int x = 1;
T a(x);
const T b_aux(x); /* Capture value of x = 1 */
T b(b_aux);
#pragma omp threadprivate(a, b)
void f(int n) {
x++;
#pragma omp parallel for
/* In each thread:
* Object a is constructed from x (with value 1 or 2?)
* Object b is copy-constructed from b_aux
*/
for (int i=0; i<n; i++) {
g(a, b); /* Value of a is unspecified. */
}
}
Odwołania krzyżowe
- wątki dynamiczne
- zmienna środowiskowa OMP_DYNAMIC
2.7.2 Klauzule atrybutów udostępniania danych
Kilka dyrektyw akceptuje klauzule, które umożliwiają użytkownikowi kontrolowanie atrybutów udostępniania zmiennych przez czas trwania regionu. Klauzule atrybutu udostępniania mają zastosowanie tylko do zmiennych w zakresie leksykalnym dyrektywy, w której pojawia się klauzula. Nie wszystkie poniższe klauzule są dozwolone we wszystkich dyrektywach. Lista klauzul, które są prawidłowe w konkretnej dyrektywie, są opisane w dyrektywie.
Jeśli zmienna jest widoczna w przypadku napotkania konstrukcji równoległej lub współużytkowania pracy, a zmienna nie jest określona w klauzuli atrybutu udostępniania lub threadprivate
dyrektywy, zmienna jest współużytkowana. Zmienne statyczne zadeklarowane w dynamicznym zakresie regionu równoległego są współużytkowane. Przydzielona pamięć sterta (na przykład użycie malloc()
w języku C lub C++ lub new
operatora w języku C++) jest współużytkowana. (Wskaźnik do tej pamięci może być jednak prywatny lub udostępniony). Zmienne z automatycznym czasem trwania magazynu zadeklarowanym w zakresie dynamicznym regionu równoległego są prywatne.
Większość klauzul akceptuje argument zmiennej listy , który jest rozdzielaną przecinkami listą widocznych zmiennych. Jeśli zmienna, do którego odwołuje się klauzula atrybutu udostępniania danych, ma typ pochodzący z szablonu i nie ma żadnych innych odwołań do tej zmiennej w programie, zachowanie jest niezdefiniowane.
Wszystkie zmienne, które pojawiają się w klauzulach dyrektywy, muszą być widoczne. Klauzule mogą być powtarzane w razie potrzeby, ale nie można określić zmiennej w więcej niż jednej klauzuli, z wyjątkiem tego, że zmienna może być określona zarówno w klauzuli a, jak firstprivate
lastprivate
i.
W poniższych sekcjach opisano klauzule atrybutu udostępniania danych:
2.7.2.1 — prywatny
Klauzula private
deklaruje zmienne na liście zmiennych, które mają być prywatne dla każdego wątku w zespole. Składnia klauzuli private
jest następująca:
private(variable-list)
Zachowanie zmiennej określonej w klauzuli private
jest następujące. Nowy obiekt z automatycznym czasem trwania magazynu jest przydzielany do konstrukcji. Rozmiar i wyrównanie nowego obiektu są określane przez typ zmiennej. Ta alokacja występuje raz dla każdego wątku w zespole, a domyślny konstruktor jest wywoływany dla obiektu klasy w razie potrzeby; w przeciwnym razie wartość początkowa jest nieokreślona. Oryginalny obiekt, do których odwołuje się zmienna, ma nieokreśloną wartość po wejściu do konstrukcji, nie może być modyfikowany w dynamicznym zakresie konstrukcji i ma nieokreśloną wartość po wyjściu z konstrukcji.
W zakresie leksykalnym konstrukcji dyrektywy zmienna odwołuje się do nowego obiektu prywatnego przydzielonego przez wątek.
Ograniczenia klauzuli private
są następujące:
Zmienna o typie klasy określonym w klauzuli
private
musi mieć dostępny, jednoznaczny konstruktor domyślny.Zmienna określona w klauzuli
private
nie może mieć typu kwalifikowanegoconst
, chyba że ma typ klasy z składowąmutable
.Zmienna określona w klauzuli
private
nie może mieć niekompletnego typu ani typu odwołania.Zmiennych, które pojawiają się w
reduction
klauzuliparallel
dyrektywy, nie można określić wprivate
klauzuli dotyczącej dyrektywy udostępniania pracy, która wiąże się z konstrukcją równoległą.
2.7.2.2 — firstprivate
Klauzula firstprivate
zawiera nadzbiór funkcji udostępnianych przez klauzulę private
. Składnia klauzuli firstprivate
jest następująca:
firstprivate(variable-list)
Zmienne określone na liście zmiennych mają private
semantyka klauzul, zgodnie z opisem w sekcji 2.7.2.1. Inicjowanie lub budowa odbywa się tak, jakby były wykonywane raz na wątek, przed wykonaniem wątku konstrukcji. firstprivate
W przypadku klauzuli na konstrukcji równoległej początkowa wartość nowego obiektu prywatnego jest wartością oryginalnego obiektu, który istnieje bezpośrednio przed konstrukcją równoległą dla wątku, który go napotka. firstprivate
W przypadku klauzuli dotyczącej konstrukcji udostępniania pracy początkowa wartość nowego obiektu prywatnego dla każdego wątku wykonującego konstrukcję udostępniania pracy jest wartością oryginalnego obiektu, który istnieje przed punktem w czasie, w którym ten sam wątek napotka konstrukcję udostępniania pracy. Ponadto w przypadku obiektów języka C++ nowy obiekt prywatny dla każdego wątku jest kopiowany z oryginalnego obiektu.
Ograniczenia klauzuli firstprivate
są następujące:
Zmienna określona w klauzuli
firstprivate
nie może mieć niekompletnego typu ani typu odwołania.Zmienna o typie klasy, który jest określony jako
firstprivate
musi mieć dostępny, jednoznaczny konstruktor kopiowania.Zmienne, które są prywatne w regionie równoległym lub które pojawiają się w
reduction
klauzuliparallel
dyrektywy, nie można określić wfirstprivate
klauzuli dotyczącej dyrektywy udostępniania pracy, która wiąże się z konstrukcją równoległą.
2.7.2.3 ostatnia prywatna
Klauzula lastprivate
zawiera nadzbiór funkcji udostępnianych przez klauzulę private
. Składnia klauzuli lastprivate
jest następująca:
lastprivate(variable-list)
Zmienne określone na liście zmiennych mają private
semantyka klauzuli. Gdy klauzula lastprivate
pojawia się w dyrektywie, która identyfikuje konstrukcję udostępniania pracy, wartość każdej lastprivate
zmiennej z sekwencyjnie ostatniej iteracji skojarzonej pętli lub leksykacyjnie ostatnia dyrektywa sekcji jest przypisywana do oryginalnego obiektu zmiennej. Zmienne, które nie mają przypisanej wartości przez ostatnią iterację for
obiektu lub parallel for
lub przez ostatnią sekcję sections
dyrektywy lub parallel sections
, mają nieokreślone wartości po konstrukcji. Nieprzypisane podobiekty również mają nieokreśloną wartość po konstrukcji.
Ograniczenia klauzuli lastprivate
są następujące:
Wszystkie ograniczenia dotyczące
private
zastosowania.Zmienna z typem klasy określonym jako
lastprivate
musi mieć dostępny, jednoznaczny operator przypisania kopiowania.Zmienne, które są prywatne w regionie równoległym lub które pojawiają się w
reduction
klauzuliparallel
dyrektywy, nie można określić wlastprivate
klauzuli dotyczącej dyrektywy udostępniania pracy, która wiąże się z konstrukcją równoległą.
2.7.2.4 — udostępnione
Ta klauzula udostępnia zmienne, które są wyświetlane na liście zmiennych wśród wszystkich wątków w zespole. Wszystkie wątki w zespole uzyskują dostęp do tego samego obszaru magazynu dla shared
zmiennych.
Składnia klauzuli shared
jest następująca:
shared(variable-list)
2.7.2.5 — domyślne
Klauzula default
umożliwia użytkownikowi wpływ na atrybuty udostępniania danych zmiennych. Składnia klauzuli default
jest następująca:
default(shared | none)
default(shared)
Określenie jest równoważne jawnej liście każdej aktualnie widocznej zmiennej w klauzulishared
, chyba że jest threadprivate
to lub const
-qualified. W przypadku braku klauzuli jawnej default
zachowanie domyślne jest takie samo, jak w przypadku default(shared)
określenia.
Określenie default(none)
wymaga, aby co najmniej jedna z następujących wartości miała wartość true dla każdego odwołania do zmiennej w zakresie leksykalnym konstrukcji równoległej:
Zmienna jest jawnie wymieniona w klauzuli atrybutu udostępniania danych konstrukcji zawierającej odwołanie.
Zmienna jest zadeklarowana w konstrukcji równoległej.
Zmienna to
threadprivate
.Zmienna ma -kwalifikowany
const
typ.Zmienna to zmienna sterowa pętli dla
for
pętli, która natychmiast podąża za dyrektywąfor
lubparallel for
, a odwołanie do zmiennej pojawia się wewnątrz pętli.
Określenie zmiennej w klauzuli firstprivate
, lastprivate
lub reduction
dyrektywy ujętej powoduje niejawne odwołanie do zmiennej w kontekście otaczającym. Takie niejawne odwołania podlegają również wymaganiom wymienionym powyżej.
W dyrektywie można określić tylko jedną default
klauzulę parallel
.
Domyślny atrybut udostępniania danych zmiennej można zastąpić przy użyciu private
klauzul , , firstprivate
lastprivate
, reduction
ishared
, jak pokazano w poniższym przykładzie:
#pragma omp parallel for default(shared) firstprivate(i)\
private(x) private(r) lastprivate(i)
2.7.2.6 — redukcja
Ta klauzula wykonuje redukcję zmiennych skalarnych, które pojawiają się na liście zmiennych, z operatorem op. Składnia klauzuli reduction
jest następująca:
reduction(
Op :
lista zmiennych )
Redukcja jest zwykle określana dla instrukcji z jedną z następujących form:
- x
=
x wyrażenie op - x wyrażenie binop
=
- x
=
expr op x (z wyjątkiem odejmowania) - x
++
++
x- x
--
--
x
gdzie:
x
Jedna ze zmiennych redukcji określona na liście.
lista zmiennych
Rozdzielona przecinkami lista zmiennych redukcji skalarnej.
wyrażenie
Wyrażenie z typem skalarnym, które nie odwołuje się do x.
Op
Nie przeciążony operator, ale jeden z +
, *
, -
, &
, ^
, |
, , &&
lub ||
.
binop
Nie przeciążony operator, ale jeden z +
, *
, -
, &
, ^
lub |
.
Poniżej przedstawiono przykład klauzuli reduction
:
#pragma omp parallel for reduction(+: a, y) reduction(||: am)
for (i=0; i<n; i++) {
a += b[i];
y = sum(y, c[i]);
am = am || b[i] == c[i];
}
Jak pokazano w przykładzie, operator może być ukryty wewnątrz wywołania funkcji. Użytkownik powinien zachować ostrożność, że operator określony w klauzuli reduction
pasuje do operacji redukcji.
Chociaż prawy operand ||
operatora nie ma skutków ubocznych w tym przykładzie, są one dozwolone, ale powinny być używane z ostrożnością. W tym kontekście efekt uboczny, który gwarantuje, że nie występuje podczas sekwencyjnego wykonywania pętli, może wystąpić podczas wykonywania równoległego. Ta różnica może wystąpić, ponieważ kolejność wykonywania iteracji jest nieokreślona.
Operator służy do określania początkowej wartości wszystkich zmiennych prywatnych używanych przez kompilator do redukcji i określania operatora finalizacji. Określenie operatora jawnie umożliwia określenie instrukcji redukcji poza zakresem leksykalnym konstrukcji. W dyrektywie można określić dowolną liczbę reduction
klauzul, ale zmienna może występować w co najwyżej jednej reduction
klauzuli dla tej dyrektywy.
Tworzona jest prywatna kopia każdej zmiennej na liście zmiennych, po jednym dla każdego wątku, tak jakby klauzula private
została użyta. Kopia prywatna jest inicjowana zgodnie z operatorem (zobacz poniższą tabelę).
Na końcu regionu, dla którego reduction
określono klauzulę, oryginalny obiekt jest aktualizowany w celu odzwierciedlenia wyniku połączenia oryginalnej wartości z ostateczną wartością każdego z prywatnych kopii przy użyciu określonego operatora. Operatory redukcji są skojarzone (z wyjątkiem odejmowania), a kompilator może swobodnie ponownie skojarzyć obliczenia wartości końcowej. (Częściowe wyniki redukcji odejmowania są dodawane w celu utworzenia wartości końcowej).
Wartość oryginalnego obiektu staje się nieokreślona, gdy pierwszy wątek osiągnie klauzulę zawierającą i pozostaje tak do momentu zakończenia obliczeń redukcji. Zwykle obliczenia zostaną ukończone na końcu konstrukcji; jeśli jednak klauzula reduction
jest używana na konstrukcji, do której nowait
jest również stosowany, wartość oryginalnego obiektu pozostaje nieokreślona do momentu przeprowadzenia synchronizacji bariery w celu zapewnienia, że wszystkie wątki zakończyły klauzulę reduction
.
W poniższej tabeli wymieniono operatory, które są prawidłowe i ich kanoniczne wartości inicjowania. Rzeczywista wartość inicjowania będzie zgodna z typem danych zmiennej redukcji.
Operator | Inicjowanie |
---|---|
+ |
0 |
* |
1 |
- |
0 |
& |
~0 |
| |
0 |
^ |
0 |
&& |
1 |
|| |
0 |
Ograniczenia klauzuli reduction
są następujące:
Typ zmiennych w
reduction
klauzuli musi być prawidłowy dla operatora redukcji, z wyjątkiem tego, że typy wskaźników i typy referencyjne nigdy nie są dozwolone.Zmienna określona w klauzuli
reduction
nie może byćconst
-kwalifikowana.Zmienne, które są prywatne w regionie równoległym lub które pojawiają się w
reduction
klauzuliparallel
dyrektywy, nie można określić wreduction
klauzuli dotyczącej dyrektywy udostępniania pracy, która wiąże się z konstrukcją równoległą.#pragma omp parallel private(y) { /* ERROR - private variable y cannot be specified in a reduction clause */ #pragma omp for reduction(+: y) for (i=0; i<n; i++) y += b[i]; } /* ERROR - variable x cannot be specified in both a shared and a reduction clause */ #pragma omp parallel for shared(x) reduction(+: x)
2.7.2.7 kopiowanie
Klauzula copyin
zawiera mechanizm przypisywania tej samej wartości do threadprivate
zmiennych dla każdego wątku w zespole wykonującego region równoległy. Dla każdej zmiennej określonej w copyin
klauzuli wartość zmiennej w wątku głównym zespołu jest kopiowana, tak jak w przypadku przypisania, do kopii prywatnych wątków na początku regionu równoległego. Składnia klauzuli copyin
jest następująca:
copyin(
variable-list
)
Ograniczenia klauzuli copyin
są następujące:
Zmienna określona w klauzuli
copyin
musi mieć dostępny, jednoznaczny operator przypisania kopiowania.Zmienna określona w klauzuli
copyin
musi być zmiennąthreadprivate
.
2.7.2.8 — prywatna kopia
Klauzula copyprivate
zawiera mechanizm używania zmiennej prywatnej do emisji wartości od jednego członka zespołu do innych członków. Jest to alternatywa dla zmiennej udostępnionej dla wartości podczas podawania takiej zmiennej udostępnionej byłaby trudna (na przykład w rekursji wymagającej innej zmiennej na każdym poziomie). Klauzula copyprivate
może pojawiać się tylko w single
dyrektywie.
Składnia klauzuli copyprivate
jest następująca:
copyprivate(
variable-list
)
Wpływ copyprivate
klauzuli na zmienne na jej liście zmiennych występuje po wykonaniu bloku strukturalnego skojarzonego z single
konstrukcją, a zanim którykolwiek z wątków w zespole opuścił barierę na końcu konstrukcji. Następnie we wszystkich innych wątkach w zespole dla każdej zmiennej na liście zmiennych zmienna staje się definiowana (tak jak w przypadku przypisania) z wartością odpowiedniej zmiennej w wątku, który wykonał blok strukturalny konstrukcji.
Ograniczenia klauzuli copyprivate
są następujące:
Zmienna określona w klauzuli
copyprivate
nie może być wyświetlana w klauzuliprivate
lubfirstprivate
dla tej samejsingle
dyrektywy.single
Jeśli dyrektywa z klauzulącopyprivate
zostanie napotkana w dynamicznym zakresie regionu równoległego, wszystkie zmienne określone wcopyprivate
klauzuli muszą być prywatne w kontekście otaczającym.Zmienna określona w klauzuli
copyprivate
musi mieć dostępny jednoznaczny operator przypisania kopiowania.
Powiązanie dyrektywy 2.8
Dynamiczne powiązanie dyrektyw musi być zgodne z następującymi regułami:
Dyrektywy
for
, ,sections
,master
single
, ibarrier
wiążą się z dynamicznie otaczającymparallel
elementem , jeśli istnieje, niezależnie od wartości jakiejkolwiekif
klauzuli, która może być obecna w tej dyrektywie. Jeśli obecnie nie jest wykonywany żaden region równoległy, dyrektywy są wykonywane przez zespół składający się tylko z wątku głównego.Dyrektywa
ordered
wiąże się z dynamicznie otaczającym elementemfor
.Dyrektywa
atomic
wymusza wyłączny dostęp w odniesieniu doatomic
dyrektyw we wszystkich wątkach, a nie tylko dla bieżącego zespołu.Dyrektywa
critical
wymusza wyłączny dostęp w odniesieniu docritical
dyrektyw we wszystkich wątkach, a nie tylko dla bieżącego zespołu.Dyrektywa nigdy nie może wiązać się z żadną dyrektywą poza najbliżej dynamicznie otaczającej
parallel
.
2.9 Zagnieżdżanie dyrektywy
Dynamiczne zagnieżdżanie dyrektyw musi być zgodne z następującymi regułami:
parallel
Dyrektywa dynamicznie wewnątrz innegoparallel
logicznego ustanawia nowy zespół, który składa się tylko z bieżącego wątku, chyba że zagnieżdżone równoległość jest włączona.for
,sections
isingle
dyrektywy, które wiążą się z tym samymparallel
, nie mogą być zagnieżdżone wewnątrz siebie.critical
dyrektywy o tej samej nazwie nie mogą być zagnieżdżone wewnątrz siebie. Należy pamiętać, że to ograniczenie nie jest wystarczające, aby zapobiec zakleszczeniom.for
dyrektywy ,sections
isingle
nie są dozwolone w dynamicznym zakresiecritical
,ordered
imaster
regionów, jeśli dyrektywy wiążą się z tym samymparallel
co regiony.barrier
dyrektywy nie są dozwolone w dynamicznym zakresiefor
, ,ordered
,sections
,single
master
, icritical
regionów, jeśli dyrektywy są powiązane z tymi samymiparallel
regionami.master
dyrektywy nie są dozwolone w dynamicznym zakresiefor
, isingle
dyrektywy,sections
jeślimaster
dyrektywy wiążą się z tymi samymiparallel
dyrektywami udostępniania pracy.ordered
dyrektywy nie są dozwolone w dynamicznym zakresie regionówcritical
, jeśli dyrektywy wiążą się z tymi samymiparallel
regionami.Każda dyrektywa dozwolona podczas dynamicznego wykonywania wewnątrz regionu równoległego jest również dozwolona w przypadku wykonywania poza regionem równoległym. W przypadku dynamicznego wykonywania poza regionem równoległym określonym przez użytkownika dyrektywa jest wykonywana przez zespół składający się tylko z wątku głównego.