Programowanie współbieżne i rozproszone - PowerPoint PPT Presentation

programowanie wsp bie ne i rozproszone n.
Download
Skip this Video
Loading SlideShow in 5 Seconds..
Programowanie współbieżne i rozproszone PowerPoint Presentation
Download Presentation
Programowanie współbieżne i rozproszone

play fullscreen
1 / 122
Programowanie współbieżne i rozproszone
166 Views
Download Presentation
yank
Download Presentation

Programowanie współbieżne i rozproszone

- - - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript

  1. Programowanie współbieżne i rozproszone • Współbieżność- składające się na nią zjawiska, czynnościlub działania odbywają się równocześnie. • Proces - program (procedura) w trakcie wykonywania, który może być skończony lub nieskończony. • Program współbieżny - zbiór programów sekwencyjnych wykonywanych równolegle, gdzie nie jest wymagane, aby każdy proces był wykonywany przez fizycznie odrębny procesor. • Geneza – systemy operacyjne wielozadaniowe.

  2. Termin programowanie współbieżne używa się do określenia technik i notacji programistycznych służących do wyrażania równoległości oraz rozwiązywania zagadnień związanych z powstałymi przy tym problemami synchronizacji i komunikacji. Programowanie współbieżne jest bardzo ważnym zagadnieniem, gdyż pozwala zajmować się równoległością bez wdawania się w szczegóły implementacyjne. Możliwość takiego abstrahowania okazała się na tyle użyteczna przy pisaniu programów, że nowoczesne języki programowania wyposażono już w mechanizmy programowania współbieżnego. Podstawowym problemem w programowaniu współbieżnym jest wyłączność procesów do wspólnych zasobów.

  3. Programowanie sekwencyjne a współbieżne • programowanie rozwiązań sekwencyjnych jest prostsze • prostsza analiza poprawności programu • duża liczba problemów analizowanych i rozwiązywanych za pomocą programu sekwencyjnego będzie działała wolniej, Programowanie sekwencyjne :

  4. Programowanie współbieżne: • możliwość tworzenia systemów komputerowych (programów współbieżnych) w sposób jak najbardziej efektywny, • programowania współbieżne jest znacznie trudniejsze niż programowania sekwencyjne, • trudniejsze jest dowodzenie poprawności programów współbieżnych (skomplikowana analiza poprawności programu), • współbieżność wymaga uwzględnienia trudnych do opisania zależności czasowych występujących pomiędzy poszczególnymi procesami, • brakuje metod testowych umożliwiających wykrywanie błędów synchronizacji, • konieczność specyfikacji (określenia) instrukcji, które mogą być wykonywane jednocześnie (problem wzajemnego wykluczania, sortowanie współbieżne tablic),

  5. Problemy w programowaniu współbieżnym • problemysynchronizacjiikomunikacji • problemy związane z przydziałem procesora (priorytetowanie procesów)

  6. Przykład:Złożoność obliczeniowa sekwencyjnego i równoległego algorytmu sortowania tablic.

  7. Sortowanie sekwencyjne n – elementowej tablicy (przez zamianę): dla wewnętrznej pętli sortowania – (n-1)+ (n-2)+...+1= n(n-1)/2= n2/2 Sortowanie równoległe podział tablicy na dwie tablice po n/2 elementów liczba operacji dla jednej tablicy (n/2)2/2 = n2/8 liczba operacji potrzebnych do posortowania 2 tablic n2/4 n operacji połączenia dwóch tablic

  8. Poprawności programów współbieżnych Program sekwencyjny jest poprawny, jeśli zatrzymuje się oraz drukuje poprawną wartość (wartości). To twierdzenie jest też słuszne dla pewnego rodzaju programów współbieżnych takich jak sortowanie. Cechą wielu programów współbieżnych (systemów operacyjnych, systemów czasu rzeczywistego) jest to, że nigdy się nie zatrzymują). Wówczas w abstrakcji współbieżności wyróżnimy dwa typy własności dotyczących poprawności:

  9. Własność bezpieczeństwa – program współbieżny jest bezpieczny, jeśli nigdy nie doprowadza do niepożądanego stanu. Np.:  problem wzajemnego wykluczania, problem producentów i konsumentów- każdaporcja zostanie skonsumowana w kolejności ichprodukowania. WłasnośćŻywotności– program współbieżny jest żywotny, jeśli zapewnia, że każde pożądane zdarzenie w końcu zajdzie.

  10. Przejawy braku żywotności Brak żywotności globalnej - blokada (zastój, zakleszczenie, martwy punkt) – występuje wtedy, gdy każdy proces z danego zbioru procesów jest wstrzymany w oczekiwaniu na zdarzenie, które może być spowodowane tylko przez jakiś inny proces z tego zbioru. Zjawisko blokady może być również traktowane jakoprzejawbraku bezpieczeństwa programu, jest bowiem stan niepożądany. Brak żywotności lokalnej - zagłodzenie – występuje wtedy, gdy proces nie zostaje wznowiony, mimo że zdarzenie, na które czeka, występuje dowolną liczbę razy i za każdym razem, gdy proces ten mógłby być wznowiony, jest wybierany jakiś inny czekający proces.Pomiędzy całkowitym brakiem pojęcia czasu w koncepcji żywotności, a wprowadzeniem czasu dokładnego znajduje się pojęcie uczciwości.

  11. Własność uczciwości - program współbieżny jest uczciwy (sprawiedliwy), jeśli podczas przydzielania zasobu dzielonego, w taki sam sposób traktuje wszystkie procesy. Własność ta jest szczególnym przykładem własności żywotności. Cztery rodzaje uczciwości : • uczciwośćsłaba oznacza, że w przypadku nieprzerwanego zgłaszania żądania dostępu do zasobu przez proces, zostanie ono kiedyś obsłużone, • uczciwośćmocna oznacza, że gdy proces zgłasza żądanie dostępu nieskończenie wiele razy, zostanie ono kiedyś obsłużone, • oczekiwanie liniowe oznacza, że jeśli proces zgłosi żądanie, zostanie ono obsłużone zanim dowolny inny proces zostanie obsłużony więcej niż jeden raz, • kolejka FIFO (ang. First In, First Out) oznacza, że jeśli proces zgłosi żądanie, zostanie ono obsłużone przed dowolnym innym żądanie zgłoszonym później.

  12. Poprawności programów współbieżnych Przeplot. Aby wykazać, że program współbieżny nie jest poprawny, wystarczy wskazać ciąg akcji poszczególnych procesów, które doprowadzają do stanu niepożądanego. System scentralizowany i rozproszony Programowanie współbieżne może dotyczyć systemów opartych na wspólnej pamięci (systemy scentralizowane), lub architektury wieloprocesorowej połączonej siecią komputerową (systemy rozproszone), gdzie każdy procesor dysponuje swoją pamięcią.

  13. WSPÓLNA PAMIĘĆ KANAŁ KOMUNIKACYJNY PROCESOR PROCESOR PROCESOR PROCESOR System scentralizowany

  14. SIEĆLOKALNA PROCESOR PROCESOR PROCESOR PROCESOR PAMIĘĆ PAMIĘĆ PAMIĘĆ PAMIĘĆ System rozproszony

  15. Problem wzajemnego wykluczania Zasób dzielony - wspólny obiekt, z którego może korzystać w sposób wyłączny wiele procesów. Zasób własny- obiekt, z którego korzysta (do którego ma dostęp w dowolnym czasie) tylko jeden proces. Sekcjakrytyczna - fragment procesu (ciąg instrukcji), w którym proces korzysta z zasobu dzielonego. Sekcja lokalna - fragment procesu (ciąg instrukcji), w którym proces korzysta z zasobu własnego.

  16. Problem wzajemnego wykluczaniapolega nazsynchronizowaniu N procesów, z którychkażdyw nieskończonej pętli na przemian zajmuje sięwłasnymi sprawami ( sekcja lokalna) i wykonujesekcję krytyczną, w taki sposób, aby wykonywanie sekcji krytycznych jakichkolwiekdwóch lub więcej procesów nie pokrywało się w czasie. Rozwiązanie problemu sprowadza się do specyfikacji zbioru reguł (warunków) spełnienie, których jest konieczne do tego, aby dany proces mógł wykorzystać zasób dzielony (unikając zagłodzenia). Oznacza to, że należy dokonać specyfikacji i implementacji następujących protokołów: protokołu wstępnego i protokołu końcowego.

  17. Process P1( ) Process P2( ) ......................... Process Pn() { while (TRUE) { while (TRUE) { while (TRUE ) { sekcja_lokalna; { sekcja_lokalna; { sekcja_lokalna; protokół_wstępny; protokół_wstępny; protokół_wstępny; sekcja_krytyczna; sekcja_krytyczna; sekcja_krytyczna; protokół_końcowy; protokół_końcowy; protokół_końcowy; } } } } } {

  18. Sekcjalokalna Protokółwstępny Sekcjakrytyczna Protokółkońcowy Schemat procesu

  19. Problem wzajemnego wykluczania Dany jest zbiór N współbieżnych procesów cyklicznych, N = {P1, P2,..., Pn}. Każdy z procesów w nieskończonej pętli, na przemian, wykonuje pracę: na zasobie własnym i zasobie dzielonym lub tylko na zasobach dzielonych. Ograniczenie w pracy systemu polega na tym, że w tym samym czasie tylko zbiór m procesów (m  ||M||, gdzie M jest podzbiorem zbioru N; M  N oraz moc ||M|| jest równa pojemności zasobu dzielonego) może wykorzystywać zasób dzielony.

  20. Warunki poprawnego rozwiązania problemu wzajemnego wykluczania: • procesy muszą być traktowane jako równoważne, nie mogą mieć przypisanych im statycznych priorytetów (sprawiedliwe decyzje) • żaden proces nie może wykonywać swej sekcji krytycznej nieskończenie długo, nie może ulec awarii podczas wykonywania sekcji krytycznej). Taki sam warunek dotyczy protokołów wstępnego i końcowego • jeżeli więcej niż jeden proces chce wejść do sekcji krytycznej, to decyzja o tym, który proces zostanie wybrany musi być podjęta w skończonym czasie. Natomiast, jeżeli żaden z procesów nie wykonuje sekcji krytycznej, to przy zgłoszeniu się dowolnego procesu musi być mu umożliwione wejście do sekcji krytycznej

  21. zachowanie się procesów poza sekcją krytyczną nie powinno być w żaden sposób ograniczone (luźne powiązanie procesów). Zatrzymanie się jakiegoś procesu w poza sekcją krytyczną nie może prowadzić do blokowania innych procesów • Procesy mogą się wykonywać z różnymi prędkościami. W rozwiązaniu nie wolno czynićżadnych założeń dotyczących względnej szybkości procesów. • Żywotność globalna i lokalna programu - brak blokady i zagłodzenia. • Bezpieczeństwo programu.

  22. Modele komunikacji między procesami: model pamięci współdzielonej-systemy scentralizowanych model przesyłania komunikatów - systemy rozproszone W modelu pamięci współdzielonej rolęłącza komunikacyjnego pomiędzy procesami spełnia pamięć dzielona: wymiana informacji poprzez zapisywanie i odczytywanie wartości zmiennej dzielonej udogodnienie sprzętowe - arbiter pamięci, zapewnia wyłączność odczytu lub zapisu informacji z danej komórki pamięci W modelu przesyłania komunikatów rolęłącza spełnia kanał komunikacyjny: wymiana informacji jest realizowana poprzez wysyłaniekomunikatów – nadaj(komunikat)iodbierz(komunikat).

  23. Problem wzajemnego wykluczanie w środowisku scentralizowanym poniższy algorytm nadaje się do wykorzystania na każdym komputerze niezależnie od zainstalowanego na nim systemu operacyjnego. Używa on wyłącznie instrukcji języka maszynowego udostępnionych przez komputer bez korzystania z mechanizmów wysokiego poziomu, takich jak semafory czy monitory.

  24. Program 1 int czyja_kolej=1; proces_P1 ( ) { while (1) { while (czyja_kolej =2); // aktywne oczekiwanie sekcja_krytyczna_P1; czyja_kolej =1; // protokół końcowy sekcja_lokalna_P1; } } ////////////////////////////// proces_P2 ( ) { while (1) { while (czyja_kolej =1); // aktywne oczekiwanie sekcja_krytyczna_P2; czyja_kolej =2; // protokół końcowy sekcja_lokalna_P2; } }

  25. Własności programu • program jest bezpieczny, • brak zagłodzenia, • procesy nie są luźno powiązane, pozwolenie jest przekazywane wprost od procesu do procesu, stąd: • awaria procesu w sekcji lokalnej -> blokada systemu • procesy wykorzystują zasób naprzemiennie

  26. Program 2 int k1=1, k2 =1; proces_P1 ( ) { while (1) { while (k2 =0); // aktywne oczekiwanie k1=0; sekcja_krytyczna_P1; k1=1; // protokół końcowy sekcja_lokalna_P1; } } ////////////////////////////// proces_P2 ( ) { while (1) { while (k1 =0); // aktywne oczekiwanie k2=0; sekcja_krytyczna_P2; k2=1; // protokół końcowy sekcja_lokalna_P2; } }

  27. Własności programu • program nie jest bezpieczny, • brak zagłodzenia, • procesy są luźno powiązane, pozwolenie jest przekazywane bezpośrednio od procesu do procesu, stąd: • awaria procesu w sekcji lokalnej umożliwia realizacje drugiemu procesowi • procesy nie wykorzystują zasobu naprzemiennie

  28. Program 3 int k1=1, k2 =1; proces_P1 ( ) { while (1) { k1=0; while (k2 =0); // aktywne oczekiwanie sekcja_krytyczna_P1; k1=1; // protokół końcowy sekcja_lokalna_P1; } } ////////////////////////////// proces_P2 ( ) { while (1) { k2=0; while (k1 =0); // aktywne oczekiwanie sekcja_krytyczna_P2; k2=1; // protokół końcowy sekcja_lokalna_P2; } }

  29. Własności programu program jest bezpieczny, brak zagłodzenia, możliwość wystąpienia blokady

  30. Program 4 int k1=1, k2 =1; proces_P1 ( ) { while (1) { k1=0; while (k2 =0) { k1=1; delay(n); //czasowa rezygnacja z wejścia do sekcji //aby P2 mógł wejść k1=0 } sekcja_krytyczna_P1; k1=1; // protokół końcowy sekcja_lokalna_P1; } }

  31. ////////////////////////////// proces_P2 ( ) { while (1) { k2=0; while (k1 =0) { k2=1; delay(n); //czasowa rezygnacja z wejścia do sekcji //aby P1 mógł wejść k2=0 } sekcja_krytyczna_P2; k2=1; // protokół końcowy sekcja_lokalna_P2; } }

  32. Własności programu • program jest bezpieczny, • możliwość wystąpienia ciągłego zagłodzenia dwóch procesów, co prowadzi doblokady Rozwiązanie poprawne - algorytm Dekkera - rozwiązuje problem wzajemnego wykluczania dla dwóch procesów konkurujących ze sobą o dostęp do zasobu dzielonego przy użyciu trzech zmiennych.

  33. Własności algorytmu Dekkera • własność bezpieczeństwa: wzajemnego wykluczania, • nie występuje w nim blokada, • żaden proces w nim nie zostanie zagłodzony • przy braku współzawodnictwa proces może natychmiast wejść do swojej sekcji krytycznej • posiada możliwość zastosowania na każdym komputerze WADA: wymaga on aktywnego oczekiwania, czyli pracy procesu w pętli w oczekiwaniu na zmianę lokacji w pamięci, co jest bardzo niepożądane ze względu na marnotrawstwo czasu procesora.

  34. W algorytmie tym prawo do nalegania na wejście do sekcji krytycznej jest jawnie przekazywane między procesami za pomocą zmiennych K1 i K2. Zmienne te zapewniają już wzajemne wykluczanie, ale po wykryciu współzawodnictwa proces np. P1 sprawdza w dodatkowej zmiennej globalnej czyja_kolej , czy teraz jest jego kolej na wejście do sekcji krytycznej. Jeśli nie to przywraca początkową wartość zmiennej K1 ustępując w ten sposób procesowi P2 i przechodzi w pętlę oczekiwania na swoją kolej. Gdy P2 kończy swoją sekcję krytyczną zmienia zmienną czyja_kolej na 1, dopuszczając proces P1 do jego sekcji krytycznej. Nawet, gdy proces P2 natychmiast zgłosi swoje żądanie na ponowne wejście do sekcji krytycznej, zostanie on powstrzymany przez zmienną czyja_kolej, gdy tylko P1 ponownie zgłosi swoje żądanie. Jeżeli jednak proces P2 pierwszy opuści swoją sekcję lokalną przed procesem P1 (proces P1 jeszcze nie nalega na wejście do sekcji krytycznej, tzn. jest jeszcze w swojej sekcji lokalnej - nie wykonał jeszcze instrukcji K1=0;) może on wejść do swojej sekcji krytycznej, pomimo że nie była to jego kolej.

  35. Wysokopoziomowe mechanizmy synchronizacji Semafory Semafor - abstrakcyjny typ danych zdefiniowany przez Dijkstrę. Semafor s jest zmienną przyjmującą (w zależności od rodzaju) wartości całkowite nieujemne lub wartości logiczne. nadanie wartości początkowej zmiennej całkowitej (semaforowej), podnoszenie semafora opuszczanie semafora Wszystkie operacje semafora są atomowe, co oznacza, iż nie mogą być wykonywane w tym samym czasie przez więcej, niż jeden proces.

  36. Oznaczenie operacji: - Nadanie wartości początkowej(s): sem s=1 //{0,1} - Czekaj(s) : wait (s), P(s) - Sygnalizuj(s) : signal(s), V(s) Operacja Czekaj(s) (zwana również z ang. Wait(s)) określona jest następująco: Znaczenie operacji “zmniejsz s” określone jest w zależności od rodzaju semafora.

  37. Operacja Sygnalizuj(s): (Signal(s)): • jeżeli istnieją procesy zawieszone przez semafor (na skutek wykonania operacji Czekaj(s)), to wznów jeden z nich • w przeciwnym przypadku zwiększ wartość s. Definicja nie określa, który proces zostanie wznowiony. Znaczenie operacji “zwiększ s” określone jest w zależności od rodzaju semafora.

  38. Istnieją procesy zawieszone przez semafor S po zwiększeniu przekraczałoby maksymalną dopuszczalną wartość Wznów jeden z zawieszonych procesów Wygeneruj błąd Zwiększ S Ogólny schemat działania semafora

  39. Semafor binarny Przyjmuje tylko wartości logiczne: prawda oraz fałsz. • Sygnalizuj(s): • jeżeli istnieją procesy zawieszone przez semafor, to wznów jeden z nich, w przeciwnym przypadku nadaj s wartość prawda

  40. Semafor ogólny Wartość początkowa jest liczbą nieujemną. Operacje elementarne przyjmują postać: Sygnalizuj(S): • jeżeli istnieją procesy zawieszone przez semafor, to wznów jeden z nich, w przeciwnym przypadku zwiększ wartość s o jeden (s = s + 1) Sposoby realizacji wznawiania procesów zawieszonych na semaforze.

  41. Semafory ze zbiorem oczekujących Procesy zawieszone umieszczane są w zbiorze zawieszonych procesów. Wznowienie procesu nie określa, który z nich ma kontynuować działanie. Semafor tego typu łatwo może więc doprowadzić do zagłodzenia przy obecności co najmniej trzech procesów. Zaletą tego semafora jest prostota realizacji i nieznacznie większa szybkość w porównaniu z semaforem z kolejką oczekujących. Semafory z kolejką oczekujących Procesy zawieszone umieszczane są w kolejce FIFO. O kolejności wznawiania decyduje pozycja w tej kolejce – najpóźniej zawieszony proces zostaje wznowiony. Zaletą tego semafora jest brak możliwości zagłodzenia jakiegokolwiek procesu. Zastosowanie semafora Semafor znajduje zastosowanie do wzajemnego wykluczania procesów przy próbie wejścia do sekcji krytycznej, umożliwiając jej wykonanie w danym czasie tylko określonej (przez wartość początkową) liczbie procesów. Jest on również wykorzystywany w celu wymiany informacji między procesami.

  42. P(S) V(S) S=0 Ktoś czeka S:=S-1 S:=S-1 Zasadę działania operacji semaforowych można przedstawić na rysunku: Proces A Proces B Zasada działania operacji semaforowych

  43. Strukturalne mechanizmy synchronizacji Rejony krytyczne Rejony krytyczne (ang. critical regions) zaproponowaliniezależnie Hoare i Brinch Hansen. Stanowią one czyste przemodelowanie operacji semaforowych Dijkstry P i V w kierunku strukturalizacji. Punktem wyjścia do ustalenia odpowiedniej notacji językowej było stworzenie instrukcji, którą obejmowałaby sekcję krytyczną, zapewniając dla niej wykluczenie wzajemne. Sekcja krytyczna najczęściej służy do wykonania operacji na pewnym zasobie, a mówiąc językiem „programowania" — na pewnej zmiennej określonego typu. Co więcej zazwyczaj jest niedopuszczalne operowanie na tym obiekcie poza sekcją krytyczną.

  44. Struktura rejonu krytycznego Obiekt typu T, na którym są wykonywane operacje wewnątrz sekcji krytycznej, nazywamy zmienną dzieloną (ang. shared variable). Jej deklaracja w postaci var v: sharedT; oznacza zadeklarowanie zmiennej v typu T, która może być używana wyłącznie w określonych sekcjach krytycznych. Instrukcja strukturalna, tworząca sekcję krytyczną dla instrukcji I1,...,IN związuje ją jednocześnie ze zmienną dzieloną v region v doI1;...; IN end Instrukcję tę nazywamy instrukcją rejonu krytycznego (lub krócej rejonem krytycznym).

  45. Założenia dotyczące rejonu krytycznego są określone trzema warunkami: (1) Wykonywanie instrukcji wewnątrz rejonów związanych z tą samą zmienną dzieloną w tym samym czasie przez dwa lub więcej procesów jest wykluczające się (inaczej mówiąc wewnątrz związanych ze sobą rejonów krytycznych może pracować co najwyżej jeden proces). (2) Proces może przebywać wewnątrz rejonu krytycznego w skończonym czasie, czyli instrukcje operujące na zmiennej dzielonej muszą mieć możliwość kończenia się. (3) Wejście do rejonu krytycznego musi być umożliwione dowolnemu procesowi w skończonym czasie. Warto zauważyć, że powyższa notacja pozwala kompilatorowi języka, w którym zostałaby zastosowana, na sprawdzenie, czy odwołania do zmiennych dzielonych są dokonywane wyłącznie z instrukcji zawartych wewnątrz odpowiednich rejonów krytycznych.

  46. Rejony krytyczne mogą być wewnątrz siebie zagłębiane na podobnych zasadach jak instrukcje cyklu w większości języków programowania. var z1, z2; shared resource; procedure p; begin region z1 do . . . region z2 do . . . end; (*z2*) end (*z1*) end; (*p*)

  47. Zastosowanie rejonów krytycznych Przeznaczeniem rejonów krytycznych jest zapewnienie wykluczenia wzajemnego procesów, które korzystają z tego samego zasobu. PRZYKŁADSynchronizacja dostępu do zasobów Należy zsynchronizować dostęp N procesów współbieżnychdo zasobu R. var R: sharedresource; procedure pp; begin cycle przetwarzanie-A; region R do request R; hold(t); release R end; przetwarzanie-B end end; process ( 1..N) pp end.

  48. PRZYKŁAD Producent—konsument Dla uproszczenia przyjmiemy, że operowanie na buforze dla wszystkich procesów producenta i konsumenta powinno odbywaćsię wewnątrz sekcji krytycznej. const N = MAX var R shared record buf: array [1..N]of buffer; lp, lk: integer :=1,1 end; pełny, pusty: semaphore:=0, N; procedure producent; begin cycle (* przygotowywanie wiadomości*) hold(t1); (*wysłaniewiadomości*) P (pusty);

  49. region R do fill buf [lp]; hold(t2); release buf [Ip]: lp := lp modN+1 end; V (pełny) end end; (*producent*) procedure konsument; begin cycle (* odebranie wiadomości*) P (pełny); region R do quit buf [lk]; hold(t3); release buf [lk]; lk := lk mod N+1 end; V (pusty); (*przetwarzanie *) hold(t4) end end; (*konsument*) process (1 .. P)producent; (1 .. K)konsument end.

  50. Warunkowe rejony krytyczne Niekompletność rejonów krytycznych, polegająca na braku prostej komunikacji między procesami, spowodowała rozwój prac nad ich uzupełnieniem o odpowiednie mechanizmy komunikacyjne. Pierwsze postulaty rozszerzeń zaproponował Hoare , natomiast szerokiego ich rozwinięcia i wzbogacenia o nowe elementy dokonał Brinch Hansen. Powstałe w ten sposób konstrukcje, jakkolwiek mające często różny zapis, otrzymały nazwę warunkowych rejonów krytycznych (ang. conditional critical regions).