Programowanie współbieżne i rozproszone/PWR Wykład 10: Różnice pomiędzy wersjami
Nie podano opisu zmian |
Nie podano opisu zmian |
||
Linia 33: | Linia 33: | ||
Gdy proces, który przebywał w monitorze, opuści go, czyli gdy następuje powrót z wywołanej funkcji/procedury monitora do procesu, pierwszy proces w kolejce procesów oczekujących na wejście do monitora jest automatycznie budzony. I znów dzieje się to automatycznie, programista nie musi się o to martwić. | Gdy proces, który przebywał w monitorze, opuści go, czyli gdy następuje powrót z wywołanej funkcji/procedury monitora do procesu, pierwszy proces w kolejce procesów oczekujących na wejście do monitora jest automatycznie budzony. I znów dzieje się to automatycznie, programista nie musi się o to martwić. | ||
=== Zmienne warunkowe === | |||
Często oprócz zapewnienia wyłącznego dostępu do zmiennych dzielonych zachodzi także potrzeba synchronizacji procesów w inny sposób. Proces musi na przykład poczekać na dostępność pewnych zasobów lub zakończenie przetwarzania przez inne procesy. Aby realizować tego typu zadania, monitor oferuje specjalny typ danych, tzw. ''zmienne warunkowe''. | |||
Zmienne warunkowe deklarujemy jako zmienne typu ''condition''. Mogą one wystepować jedynie wewnątrz moniora. Na zmiennej warunkowej c proces może wykonać następujące operacje: | |||
# wait (c). Powoduje wstrzymanie działania procesu, który ją wykonał. Proces opuszcza chwilowo monitor (tym samym może do niego wejść inny proces z kolejki procesów oczekujących na wejście) i zostaje wstrzymany w kolejce prostej związanej ze zmienną warunkową c. | |||
# empty(c). Jest to funkcja logiczna przekazująca w wyniku informacje, czy są procesy oczekujące na zmiennej warunkowej c. | |||
# signal(c). Powoduje obudzenie pierwszego procesu z kolejki procesów oczekujących na zmiennej warunkowej c. Jeśli kolejka jest pusta, to instrukcja nie daje żadnego efektu. Obudzony proces natychmiast wznawia swoje działanie w monitorze od kolejnej instrukcji za wait, w którym został wstrzymany. | |||
=== Uproszczona semantyka instrukcji signal === | === Uproszczona semantyka instrukcji signal === | ||
Bliższa analiza działania | |||
=== Pełna semantyka instrukcji signal === | === Pełna semantyka instrukcji signal === |
Wersja z 11:16, 3 paź 2006
Monitory
Podstawową wadą semafora jest to, że nie jest to mechanizm strukturalny, przez co trudno jest analizować programy współbieżne i ogarnąć wszystkie możliwe przeploty. Dochodzą do tego częste błędy polegające chociażby na niezamierzonej zamianie operacji P i V ze sobą.
Monitor jako moduł programistyczny
Powyższych wad jest pozbawiony monitor, który stanowi połączenie modułu programistycznego z sekcją krytyczną. Monitor jest po prostu modułem zawierającym deklaracje stałych, zmiennych, funkcji i procedur. Wszystkie te obiekty, z wyjątkiem jawnie wskazanych funkcji i procedur są lokalne w monitorze i nie są widoczne na zewnątrz niego. Wskazane funkcje i procedury (tzw. eksportowane) są widoczne na zewnątrz monitora. Mogą je wywoływać procesy i za ich pośrednictwem manipulować danymi ukrytymi w monitorze. Monitor zawiera też kod, który służy do jego inicjacji, na przykład do ustawienia wartości początkowych zmiennych deklarowanych w monitorze.
Monitor będziemy definiować korzystając z następującej składni:
monitor Nazwa; definicje stałych i typów; deklaracje zmiennych lokalnych; deklaracje procedur i funkcji; begin instrukcje inicjujące monitor; end;
Definiując stałe, typy, zmienne i procedury będziemy stosować składnię Pascala z tym, że procedury i funkcje udostępniane na zewnątrz będziemy poprzedzać słowem kluczowym export.
Aby wywołać eksportowaną przez monitor M procedurę P w pewnym procesie użyjemy notacji:
M.P (parametry)
Z powyższego opisu wynika, że monitor jest po prostu modułem, ukrywającym część informacji i udostępniającym na zewnątrz pewne funkcje i procedury. Ale to nie są jeszcze wszystkie własności monitora.
Monitor jako sekcja krytyczna
Monitor jest z definicji sekcją krytyczną. Co to oznacza? Otóż jednocześnie co najwyżej jeden proces może być w trakcie wykonania kodu znajdującego się w monitorze. Innymi słowy: jeśli jakiś proces wywoła procedurę eksportowaną przez monitor M i rozpocznie jej wykonanie, to do czasu powrotu z tej procedury żaden inny proces nie może rozpocząć wykonania tej ani żadnej innej procedury/ funkcji monitora. O procesie, który wywołał funkcję/procedurę monitora i nie zakończył jeszcze jej wykonania, będziemy mówić, że znajduje się w monitorze. Zatem jednocześnie w monitorze może przebywać co najwyżej jeden proces.
Taka definicja narzuca sposób naturalny sposób korzystania ze zmiennych współdzielonych przez procesy. Po prostu należy umieścić je w monitorze i dostęp do nich realizować za pomocą eksportowanych procedur i funkcji. Programista korzystający w taki właśnie sposób ze zmiennej dzielonej nie musi myśleć o zapewnianiu wyłączności w dostępie do niej --- robi to za niego automatycznie sam monitor.
Co się jednak dzieje, jeśli pewien proces wywoła procedurę monitora w chwili, gdy inny proces już się w nim znajduje? Otóż taki proces musi poczekać. Z każdym monitorem jest związana kolejka procesów oczekujących na "wejście" do niego. Jest to kolejka prosta: proces, który zgłosił się jako pierwszy i został wstrzymany przed wejściem do monitora, jako pierwszy zostanie wznowiony. Zaznaczmy, niezależnie od tego, którą procedurę czy funkcję monitora proces wywołał, zostanie on w razie konieczności wstrzymany i umieszczony w tej samej kolejce. Jest jedna kolejka procesów oczekujących na wejście do monitora, a nie tak jak w Adzie, osobne kolejki do poszczególnych procedur eksportowanych.
Gdy proces, który przebywał w monitorze, opuści go, czyli gdy następuje powrót z wywołanej funkcji/procedury monitora do procesu, pierwszy proces w kolejce procesów oczekujących na wejście do monitora jest automatycznie budzony. I znów dzieje się to automatycznie, programista nie musi się o to martwić.
Zmienne warunkowe
Często oprócz zapewnienia wyłącznego dostępu do zmiennych dzielonych zachodzi także potrzeba synchronizacji procesów w inny sposób. Proces musi na przykład poczekać na dostępność pewnych zasobów lub zakończenie przetwarzania przez inne procesy. Aby realizować tego typu zadania, monitor oferuje specjalny typ danych, tzw. zmienne warunkowe.
Zmienne warunkowe deklarujemy jako zmienne typu condition. Mogą one wystepować jedynie wewnątrz moniora. Na zmiennej warunkowej c proces może wykonać następujące operacje:
- wait (c). Powoduje wstrzymanie działania procesu, który ją wykonał. Proces opuszcza chwilowo monitor (tym samym może do niego wejść inny proces z kolejki procesów oczekujących na wejście) i zostaje wstrzymany w kolejce prostej związanej ze zmienną warunkową c.
- empty(c). Jest to funkcja logiczna przekazująca w wyniku informacje, czy są procesy oczekujące na zmiennej warunkowej c.
- signal(c). Powoduje obudzenie pierwszego procesu z kolejki procesów oczekujących na zmiennej warunkowej c. Jeśli kolejka jest pusta, to instrukcja nie daje żadnego efektu. Obudzony proces natychmiast wznawia swoje działanie w monitorze od kolejnej instrukcji za wait, w którym został wstrzymany.
Uproszczona semantyka instrukcji signal
Bliższa analiza działania