Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować się zalogować lub zmienić katalog.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
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
ifjest obecna. - Wyrażenie
ifoblicza 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_threadsjest obecna, wartość wyrażenia całkowitego jest liczbą żądanych wątków.omp_set_num_threadsJeś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_THREADSjest 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
ifklauzula może pojawić się w dyrektywie.Nie określono, czy występują jakiekolwiek skutki uboczne wewnątrz wyrażenia if lub
num_threadswyrażenia.throwWykonanie 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_threadsklauzula może pojawić się w dyrektywie. Wyrażenienum_threadsjest obliczane poza kontekstem regionu równoległego i musi zostać obliczone na dodatnią wartość całkowitą.Kolejność oceny
ifklauzul inum_threadsjest nieokreślona.
Odwołania krzyżowe
-
private, ,firstprivate,defaultshared,copyin, ireductionklauzule (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 = funt
- 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-+ 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 |
|---|---|
| statyczny | 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
formusi być blokiem ustrukturyzowanym, a ponadto jej wykonanie nie może zostać zakończone przez instrukcjębreak.Wartości wyrażeń sterujących
forpętli skojarzonej z dyrektywąformuszą być takie same dla wszystkich wątków w zespole.Zmienna
foriteracji pętli musi mieć podpisany typ liczby całkowitej.Tylko jedna
scheduleklauzulaformoże pojawić się w dyrektywie.Tylko jedna
orderedklauzulaformoże pojawić się w dyrektywie.Tylko jedna
nowaitklauzulaformoż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, ,firstprivatelastprivateireductionklauzule (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:
sectionDyrektywa nie może znajdować się poza zakresemsectionsleksykalnym dyrektywy.Tylko jedna
nowaitklauzulasectionsmoże pojawić się w dyrektywie.
Odwołania krzyżowe
-
private, ,firstprivatelastprivateireductionklauzule (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
nowaitklauzulasinglemoże pojawić się w dyrektywie. - Klauzula
copyprivatenie może być używana z klauzuląnowait.
Odwołania krzyżowe
-
private,firstprivateicopyprivateklauzule (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 dyrektywy iparallel, z wyjątkiem klauzuli sections .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
flushw 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ą orderedordered 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ą
fornie może wykonywać tej samej uporządkowanej dyrektywy więcej niż raz i nie może wykonywać więcej niż jednejordereddyrektywy.
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:
threadprivateDyrektywa 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
threadprivatezmiennych 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ę.threadprivateDyrektywa 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
threadprivatezmiennych 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
threadprivatedyrektywie w jednej jednostce tłumaczenia, musi być określona wthreadprivatedyrektywie w każdej jednostce tłumaczenia, w której jest zadeklarowana.Zmienna nie może być wyświetlana
threadprivatew żadnej klauzuli z wyjątkiemcopyinklauzuli ,copyprivate,schedule,num_threadslub klauzuliif.Adres zmiennej
threadprivatenie jest stałą adresu.Zmienna
threadprivatenie może mieć niekompletnego typu ani typu odwołania.Zmienna
threadprivateo 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 firstprivatelastprivate 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
privatemusi mieć dostępny, jednoznaczny konstruktor domyślny.Zmienna określona w klauzuli
privatenie może mieć typu kwalifikowanegoconst, chyba że ma typ klasy z składowąmutable.Zmienna określona w klauzuli
privatenie może mieć niekompletnego typu ani typu odwołania.Zmiennych, które pojawiają się w
reductionklauzuliparalleldyrektywy, nie można określić wprivateklauzuli 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ą semantyka klauzul, zgodnie z opisem w private. 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
firstprivatenie może mieć niekompletnego typu ani typu odwołania.Zmienna o typie klasy, który jest określony jako
firstprivatemusi mieć dostępny, jednoznaczny konstruktor kopiowania.Zmienne, które są prywatne w regionie równoległym lub które pojawiają się w
reductionklauzuliparalleldyrektywy, nie można określić wfirstprivateklauzuli 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 forlub 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
privatezastosowania.Zmienna z typem klasy określonym jako
lastprivatemusi mieć dostępny, jednoznaczny operator przypisania kopiowania.Zmienne, które są prywatne w regionie równoległym lub które pojawiają się w
reductionklauzuliparalleldyrektywy, nie można określić wlastprivateklauzuli 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
consttyp.Zmienna to zmienna sterowa pętli dla
forpętli, która natychmiast podąża za dyrektywąforlubparallel for, a odwołanie do zmiennej pojawia się wewnątrz pętli.
Określenie zmiennej w klauzuli firstprivate, lastprivatelub 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 privateklauzul , , firstprivatelastprivate, reductionishared, 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
=xwyrażenie op -
x wyrażenie binop
= -
x
=expropx (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.
| Obsługujący | Inicjowanie |
|---|---|
+ |
0 |
* |
1 |
- |
0 |
& |
~0 |
| |
0 |
^ |
0 |
&& |
1 |
|| |
0 |
Ograniczenia klauzuli reduction są następujące:
Typ zmiennych w
reductionklauzuli 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
reductionnie może byćconst-kwalifikowana.Zmienne, które są prywatne w regionie równoległym lub które pojawiają się w
reductionklauzuliparalleldyrektywy, nie można określić wreductionklauzuli 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
copyinmusi mieć dostępny, jednoznaczny operator przypisania kopiowania.Zmienna określona w klauzuli
copyinmusi 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
copyprivatenie może być wyświetlana w klauzuliprivatelubfirstprivatedla tej samejsingledyrektywy.singleJeśli dyrektywa z klauzulącopyprivatezostanie napotkana w dynamicznym zakresie regionu równoległego, wszystkie zmienne określone wcopyprivateklauzuli muszą być prywatne w kontekście otaczającym.Zmienna określona w klauzuli
copyprivatemusi 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,singlemaster, ibarrierwiążą się z dynamicznie otaczającymparallelelementem , jeśli istnieje, niezależnie od wartości jakiejkolwiekifklauzuli, 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
orderedwiąże się z dynamicznie otaczającym elementemfor.Dyrektywa
atomicwymusza wyłączny dostęp w odniesieniu doatomicdyrektyw we wszystkich wątkach, a nie tylko dla bieżącego zespołu.Dyrektywa
criticalwymusza wyłączny dostęp w odniesieniu docriticaldyrektyw 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:
parallelDyrektywa dynamicznie wewnątrz innegoparallellogicznego 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,sectionsisingledyrektywy, które wiążą się z tym samymparallel, nie mogą być zagnieżdżone wewnątrz siebie.criticaldyrektywy 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.fordyrektywy ,sectionsisinglenie są dozwolone w dynamicznym zakresiecritical,orderedimasterregionów, jeśli dyrektywy wiążą się z tym samymparallelco regiony.barrierdyrektywy nie są dozwolone w dynamicznym zakresiefor, ,ordered,sections,singlemaster, icriticalregionów, jeśli dyrektywy są powiązane z tymi samymiparallelregionami.masterdyrektywy nie są dozwolone w dynamicznym zakresiefor, isectionsdyrektywy,singlejeślimasterdyrektywy wiążą się z tymi samymiparalleldyrektywami udostępniania pracy.ordereddyrektywy nie są dozwolone w dynamicznym zakresie regionówcritical, jeśli dyrektywy wiążą się z tymi samymiparallelregionami.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.