Programowanie współbieżne i równoległe. Część 2



Podobne dokumenty
Programowanie równoległe i rozproszone. Monitory i zmienne warunku. Krzysztof Banaś Programowanie równoległe i rozproszone 1

Współbieżność i równoległość w środowiskach obiektowych. Krzysztof Banaś Obliczenia równoległe 1

Obliczenia równoległe i rozproszone w JAVIE. Michał Kozłowski 30 listopada 2003

Autor: dr inż. Zofia Kruczkiewicz, Programowanie aplikacji internetowych 1

Współbieżność w środowisku Java

Programowanie równoległe i rozproszone. W1. Wielowątkowość. Krzysztof Banaś Programowanie równoległe i rozproszone 1

Wielowątkowość mgr Tomasz Xięski, Instytut Informatyki, Uniwersytet Śląski Katowice, 2011

Wątek - definicja. Wykorzystanie kilku rdzeni procesora jednocześnie Zrównoleglenie obliczeń Jednoczesna obsługa ekranu i procesu obliczeniowego

Semafor nie jest mechanizmem strukturalnym. Aplikacje pisane z użyciem semaforów są podatne na błędy. Np. brak operacji sem_post blokuje aplikację.

Systemy operacyjne. Zajęcia 11. Monitory

Semafor nie jest mechanizmem strukturalnym. Aplikacje pisane z użyciem semaforów są podatne na błędy. Np. brak operacji sem_post blokuje aplikację.

Ingerencja w kod systemu operacyjnego (przerwania) Programowanie na niskim poziomie (instrukcje specjalne) Trudności implementacyjne (alg.

Kurs programowania. Wykład 8. Wojciech Macyna

Język Java wątki (streszczenie)

Programowanie współbieżne Wykład 10 Synchronizacja dostępu do współdzielonych zasobów. Iwona Kochańska

Programowanie współbieżne Wykład 5. Rafał Skinderowicz

Monitory. Jarosław Kuchta

Stworzenie klasy nie jest równoznaczne z wykorzystaniem wielowątkowości. Uzyskuje się ją dopiero poprzez inicjalizację wątku.

Kurs programowania. Wykład 8. Wojciech Macyna. 10 maj 2017

Wątki w Javie. Piotr Tokarski

Programowanie wielowątkowe. Tomasz Borzyszkowski

Współbieżność w Javie

Przeplot. Synchronizacja procesów. Cel i metody synchronizacji procesów. Wątki współbieżne

1 Wątki 1. 2 Tworzenie wątków 1. 3 Synchronizacja 3. 4 Dodatki 3. 5 Algorytmy sortowania 4

Język Java wątki (streszczenie)

Współbieżność w Javie

Wykład 5. Synchronizacja (część II) Wojciech Kwedlo, Wykład z Systemów Operacyjnych -1- Wydział Informatyki PB

Synchronizacja procesów i wątków

Języki i Techniki Programowania II. Wykład 7. Współbieżność 1

Przetwarzanie wielowątkowe przetwarzanie współbieżne. Krzysztof Banaś Obliczenia równoległe 1

4. Procesy pojęcia podstawowe

Java. Wykład. Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ

Wątki. Definiowanie wątków jako klas potomnych Thread. Nadpisanie metody run().

Programowanie komputerów

Programowanie współbieżne i rozproszone

Wprowadzenie do programowania współbieżnego

Mechanizmy pracy równoległej. Jarosław Kuchta

4. Procesy pojęcia podstawowe

Wielowątkowość. Programowanie w środowisku rozproszonym. Wykład 1.

Programowanie współbieżne Wykład 9 Synchronizacja dostępu do współdzielonych zasobów. Iwona Kochańska

Systemy operacyjne III

Podstawy współbieżności

Programowanie Równoległe i Rozproszone

Wykład 4. Synchronizacja procesów (i wątków) cześć I. Wojciech Kwedlo, Wykład z Systemów Operacyjnych -1- Wydział Informatyki PB

synchronizacji procesów

Proces z sekcją krytyczną. Synchronizacja procesów. Synchronizacja procesów, cd. Synchronizacja procesów, cd. Synchronizacja procesów, cd

Aplikacje w Javie- wykład 11 Wątki-podstawy

synchronizacji procesów

Programowanie współbieżne i równoległe

Wielozadaniowość w systemie Microsoft Windows

Wstęp do programowania 2

JAVA. Java jest wszechstronnym językiem programowania, zorientowanym. apletów oraz samodzielnych aplikacji.

procesów Współbieżność i synchronizacja procesów Wykład prowadzą: Jerzy Brzeziński Dariusz Wawrzyniak

Klasyczne problemy współbieżności. Problem producenta i konsumenta Problem czytelników i pisarzy Problem pięciu filozofów

SYSTEMY OPERACYJNE WYKLAD 6 - procesy

Programowanie współbieżne i równoległe. dr inż. Marcin Wilczewski 2013

Semafory. // G - globalna dla wszystkich. // Wada - aktywne oczekiwanie Test_and_Set(Li); exit when Li = 0; end loop sekcja_krytyczna(i); G := 0;

SYSTEMY CZASU RZECZYWISTEGO - VxWorks

Współbieżność i równoległość w środowiskach obiektowych. Krzysztof Banaś Obliczenia równoległe 1

Zaawansowany kurs języka Python

Programowanie obiektowe. Literatura: Autor: dr inŝ. Zofia Kruczkiewicz

1 Atrybuty i metody klasowe

Enkapsulacja, dziedziczenie, polimorfizm

Konstruktory. Streszczenie Celem wykładu jest zaprezentowanie konstruktorów w Javie, syntaktyki oraz zalet ich stosowania. Czas wykładu 45 minut.

Interfejsy w Java. Przetwarzanie równoległe. Wątki.

WSPÓŁBIEŻNOŚĆ. MATERIAŁY:

Zaawansowane programowanie w C++ (PCP)

Programowanie w Sieci Internet. Python: Wątki. Kraków, 12 grudnia 2014 r. mgr Piotr Rytko Wydział Matematyki i Informatyki

4. Procesy pojęcia podstawowe

Wykład 8: klasy cz. 4

Informatyka I. Klasy i obiekty. Podstawy programowania obiektowego. dr inż. Andrzej Czerepicki. Politechnika Warszawska Wydział Transportu 2018

Java. język programowania obiektowego. Programowanie w językach wysokiego poziomu. mgr inż. Anna Wawszczak

Proces z sekcją krytyczną. Synchronizacja procesów. Synchronizacja procesów, cd. Synchronizacja procesów, cd. Synchronizacja procesów, cd

4.1 Napisz kod, w którym definiujesz, tworzysz oraz uruchamiasz wątki z uŝyciem klas java.lang.thread oraz java.lang.runnable.

Multimedia JAVA. Historia

Programowanie wielowątkowe. Jarosław Kuchta

Programowanie współbieżne Wykład 7. Iwona Kochaoska

Temat zajęć: Tworzenie i obsługa wątków.

Prezentacja systemu RTLinux

Programowanie współbieżne Wykład 4. Rafał Skinderowicz

Procesy, wątki i zasoby

Monitory. Wady semafora

Programowanie obiektowe - 1.

Języki i techniki programowania Ćwiczenia 2

PARADYGMATY PROGRAMOWANIA Wykład 4

Porządek dostępu do zasobu: procesory obszary pamięci cykle procesora pliki urządzenia we/wy

Kurs rozszerzony języka Python

Lock Manager Deadlock Źródła Jak starczy czasu. Dreadlocks. Konrad Błachnio MIMUW 19 maja 2010

Obiekt klasy jest definiowany poprzez jej składniki. Składnikami są różne zmienne oraz funkcje. Składniki opisują rzeczywisty stan obiektu.

Programowanie współbieżne Zadanie 5 - Podstawowe problemy programowania współbieżnego

Pierwsze kroki. Algorytmy, niektóre zasady programowania, kompilacja, pierwszy program i jego struktura

Model pamięci. Rafał Skinderowicz

Systemy operacyjne. wykład 11- Zakleszczenia. dr Marcin Ziółkowski. Instytut Matematyki i Informatyki Akademia im. Jana Długosza w Częstochowie

Informacje ogólne. Karol Trybulec p-programowanie.pl 1. 2 // cialo klasy. class osoba { string imie; string nazwisko; int wiek; int wzrost;

SYSTEMY OPERACYJNE PROCESORÓW SYGNAŁOWYCH

JAVA W SUPER EXPRESOWEJ PIGUŁCE

Podstawy programowania. Wykład Funkcje. Krzysztof Banaś Podstawy programowania 1

Platformy Programistyczne Zagadnienia sieciowe i wątki

Laboratorium z przedmiotu Programowanie obiektowe - zestaw 04

Klasy abstrakcyjne i interfejsy

Transkrypt:

Programowanie współbieżne i równoległe Część 2 dr inż. Marcin Wilczewski 2015 1

Klasyczne problemy współbieżności. Problem producenta i konsumenta Zakładamy, że istnieje P procesów producentów oraz K procesów konsumentów. Producenci odpowiadają za wytwarzanie zasobów (obiektów), konsumenci za ich użytkowanie (niszczące) Wariant synchroniczny i asynchroniczny Problem polega na zsynchronizowaniu wszystkich P + K procesów tak, by: -Zapewnić producentom danych miejsca na zapamiętanie danych (bufor) -Operacje wstawiania i pobierania (produkcji i konsumpcji) z tego samego elementu bufora wzajemnie się wykluczały -Konsument oczekiwał na odczytanie danych w przypadku, gdy bufor jest pusty -Producent oczekiwał, gdy bufor jest pełny -Zagwarantowane były warunki żywotności oraz bezpieczeństwa 2

Klasyczne problemy współbieżności. Problem czytelników i pisarzy Problem czytelników i pisarzy stanowi abstrakcję problemu dostępu (zapisu/odczytu bazy danych) Zakładamy, że w systemie funkcjonuje C>0 czytelników, które odczytują dane oraz P>0 pisarzy, które zapisują dane Jednocześnie z czytelni może korzystać wielu czytelników Jeśli w czytelni przebywa pisarz, to żaden inny proces nie może uzyskać dostępu do czytelni Każdy czytelnik, który chce odczytać dane, w końcu je odczyta (warunek żywotności) Każdy pisarz, który chce zmodyfikować/zapisać dane, w końcu je zapisze (warunek żywotności) 3

Klasyczne problemy współbieżności. Problem czytelników i pisarzy c.d Dotychczas omawiane problemy współbieżności dotyczyły głównie przypadków zasobów z dostępem wzajemnie wykluczanym (jeden proces otrzymuje wyłączny dostęp na jednostkę czasu). Problem czytelników i pisarzy jest abstrakcją problemu dostępu do zasobu, który może być dzielony (jednoczesny dostęp do zasobu przez wiele procesów) Dwie podstawowe odmiany rozwiązania problemu czytelników i pisarzy: 1. Czytelnicy nie muszą czekać na wejście do czytelni nawet w przypadku, gdy na wejście do czytelni czeka już pisarz. Możliwe jest zagłodzenie pisarzy 2. Gdy pisarz oczekuje na wejście do czytelni żaden nowy czytelnik nie będzie mógł do niej wejść. Możliwe jest zagłodzenie czytelników 4

Semafory Historycznie pierwsze wysokopoziomowe narzędzie realizacji synchronizacji procesów (Dijkstra) Implementowane w różnych języka programowania (np. Java, C (pthread)) Semafor to zmienna całkowitoliczbowa + trzy dopuszczalne operacje Dostępne operacje: inicjalizacja, wait, signal wait(s): signal(s): jeżeli s>0, to s=s-1, w przeciwnym wypadku proces, który wykonał funkcję wait zostaje zawieszony jeżeli istnieją procesy (lub proces) zawieszone wskutek wcześniejszego wykonania operacji wait na danym semaforze, to wznów jeden z procesów zawieszonych; w przeciwnym wypadku s=s+1 Istnieją różne warianty semaforów: ogólne, binarne, uogólnione. Różne semafory wykorzystywane są do rozwiązania różnych problemów synchronizacji Definicja semafora nie specyfikuje polityki wznawiania procesów zawieszonych na semaforze. Zależy to od konkretnej implementacji 5

Semafory c.d. Semafory stanowią wysokopoziomowe narzędzie synchronizacji dostępne w systemach scentralizowanych ze wspólną pamięcią. Semafor jest obiektem współdzielonym pomiędzy synchronizowanymi wątkami/procesami Operacje opuszczania i podnoszenia danego semafora są niepodzielne (atomowe) Klasyczna definicja semafora nie dopuszcza możliwości testowania zmiennej semaforowej; istnieją implementacje dające taką możliwość Do rozwiązania pewnych problemów programowania współbieżnego konieczna jest znajomość stanu zmiennej semaforowej. W przypadku, gdy implementacja semafora jest zgodna z definicją klasyczną konieczna może być obsługa dodatkowej zmiennej globalnej ustawianej w sekcji krytycznej 6

Semafory. Rozwiązanie problemu wzajemnego wykluczania. Przykład: Po współbieżnym uruchomieniu wielu procesów semafor realizuje wzajemne wykluczanie: wyłącznie jeden wątek może wykonywać sekcję krytyczną W tym przypadku semafor jest bardzo silnym narzędziem ograniczającym dostęp do sekcji krytycznej dla co najwyżej jednego procesu/wątku Do rozwiązania problemu wzajemnego wykluczania, gdy w sekcji krytycznej może przebywać maksymalnie N procesów/wątków można wykorzystać semafor ogólny rozmiaru N (N jest wartością inicjalną takiego semafora). 7

Semafory. Problem producenta i konsumenta Wariant 1 uproszczony bufor nieograniczony, umieszczanie i pobieranie danych z bufora nie są operacjami wykonywanymi w sekcji krytycznej procesów 8

Semafory. Problem producenta i konsumenta c.d. Wykorzystany został semafor ogólny o inicjalnej wartości N Procesy konsumenta i producenta wykorzystują w tym przypadku semafor niesymetrycznie, tzn. konsument wykonuje wyłącznie operację wait(s) natomiast producent signal(s) Semafor jest w tym przypadku wykorzystywany jako zmienna zliczająca W praktyce nawet w przypadku jednego producenta i jednego konsumenta operacje wstawiania i odczytu danych do/z bufora powinny być synchronizowane. Dlaczego? 9

Semafory. Problem producenta i konsumenta c.d. Wariant 2 bufor nieograniczony, umieszczanie i pobieranie danych z bufora są operacjami wykonywanymi w sekcji krytycznej procesów 10

Semafory. Problem producenta i konsumenta c.d. W rozwiązaniu wykorzystywane są dwa semafory: binarny (wzajemne wykluczanie w dostępnie do sekcji krytycznej) oraz ogólny (zliczający) Inicjalna wartość semaforów musi być następująca: s = 1, n= 0. Dlaczego? Kolejność operacji wait oraz signal ma znaczenie. Przykład: do czego może doprowadzić zmiana kolejności instrukcji wait(n) oraz wait(s) w procesie konsumenta przed wejściem do sekcji krytycznej? 11

Semafory. Problem producenta i konsumenta c.d. Wariant 3 bufor ograniczony, umieszczanie i pobieranie danych z bufora są operacjami wykonywanymi w sekcji krytycznej procesów 12

Semafory. Problem czytelników i pisarzy Wariant 1: liczba miejsc czytelników nie jest ograniczona (ograniczeniem jest tylko typ zmiennej zdefiniowanej wewnątrz semafora) 13

Semafory. Problem czytelników i pisarzy c.d. Żaden z czytelników nie musi czekać na wejście do czytelni, o ile nie przebywa w niej pisarz. Może to doprowadzić do sytuacji zagłodzenia pisarza W przedstawionym przykładzie pisarz może rozpocząć pisanie po opuszczeniu semafora pisanie Pierwszy z czytelników przed wejściem do czytelni opuszcza semafor pisanie uniemożliwiając wejście pisarza. Jednocześnie nie ma blokady na wejście innych czytelników do czytelni (readers preference) Ostatni z czytelników przed podniesieniem semafora czytanie podnosi semafor pisanie, tym samym dając możliwość zajęcia czytelni przez oczekującego pisarza 14

Semafory. Problem czytelników i pisarzy Wariant 2 (specjalny): Znana jest liczba M czytelników lub w czytelni może przebywać co najwyżej M czytelników (M jest małe). M jest parametrem problemu W poniższym rozwiązaniu semafor e pełni rolę zmiennej zliczającej i reprezentuje bieżącą liczbę wolnych miejsc w czytelni przeznaczonych dla czytelników. Semafor s pełni rolę muteksu wzajemnie wykluczającego dostęp do sekcji pisania 15

Semafory. Problem czytelników i pisarzy c.d. Przedstawiony wariant zakłada maksymalną dopuszczalną liczbę czytelników w czytelni. Nie jest to rozwiązanie ogólne Proces czytelnika bezpośrednio nie blokuje pisarza przed dostępem do czytelni. Na procesie pisarza leży obowiązek zweryfikowania czy spełnione są warunki do rozpoczęcia pisania Wykonanie operacji wait(s) uprawnia proces pisarza do wejścia do czytelni (o ile proces nie zostanie wstrzymany na semaforze). Operację tę pisarz wykonuje w celu zdobycia na wyłączność wszystkich miejsc w czytelni (pętla for dla i = 1..M) Proces pisania nie może się rozpocząć zanim proces pisarza nie zablokuje wszystkich miejsc czytelników w czytelni (M krotne opuszczenie semafora e) Rozwiązanie nie wykorzystuje w pełni możliwości jednoczesnego czytania przez wielu czytelników: pisarz, który chce wejść do czytelni zajmuje wszystkie wolne miejsca czytelników i oczekuje na zwolnienie już wcześniej zajętych 16

Semafory. Problem czytelników i pisarzy c.d. Wariant 3: Problem czytelników i pisarzy z możliwością zagłodzenia czytelników (writer preference). Kod realizowany przez proces pisarza zapobiega wchodzeniu czytelników przed pisarzami 17

Semafory. Problem czytelników i pisarzy c.d. Pierwszy z pisarzy opuszcza semafor czytanie. Jest to równoważne z uniemożliwieniem wejścia do czytelni czytelnika przed wyjściem z czytelni tegoż pisarza. Napływający pisarze mogą zagłodzić czytelników 18

Problem czytelników i pisarzy w bazach danych Praktyczne implementacje rozwiązania problemu czytelników i pisarzy wykorzystuje się do zagwarantowania bezpiecznego, współbieżnego dostępu do danych zgromadzonych w bazach danych Transakcja bazy danych może być interpretowana jako realizacja abstrakcyjnego procesu pisarza Jednym z podstawowych własności jakie spełniają transakcje bazodanowe jest izolacja zdefiniowana jako nieuzewnętrznianie niespójnych stanów systemu bazodanowego w trakcie trwania transakcji. Z reguły poziom izolacji jest konfigurowalny Izolacja transakcji jest implementowana przez mechanizm blokad W przypadku baz danych MS SQL Server 2005/2008 poziom spójności danych przetwarzanych współbieżnie przez wiele transakcji można kontrolować przez ustawienie jednego z sześciu możliwych poziomów izolacji: read committed, read uncommitted, repetable read, serializable, snapshot oraz committed snapshot Najwyższy poziom izolacji zapewnia największą spójność danych, ale jednocześnie najmniejszy poziom współbieżności. Najniższy poziom (read uncommitted) zapewnia najwyższy poziom współbieżności i najmniejszą spójność danych 19

Problem czytelników i pisarzy w bazach danych c.d. W ogólności, zwiększenie stopnia spójności odbywa się kosztem zmniejszenia współbieżności poprzez wydłużenie czasu utrzymywania blokad na zasobach Najniższy poziom izolacji (read uncommitted) odpowiada umożliwieniu przebywania w czytelni zarówno procesów czytelników, jak i pisarzy. Wyklucza jednak możliwość jednoczesnego przebywania w czytelni wielu pisarzy Ustawienie danego poziomu izolacji determinuje zestaw potencjalnych problemów związanych ze spójnością danych, które pojawią się lub nie na etapie przetwarzania danych Dwa podstawowe typy blokad wykorzystywanych do realizacji przetwarzania współbieżnego: blokady współdzielone (shared) oraz wyłączne (exclusive) 20

Monitory Semafory stwarzają bardzo duże możliwości synchronizacji wątków, ale nie są strukturalne i dodatkowo wymagają od programistów jawnego zakładania blokad (jawne opuszczanie i podnoszenie semaforów). Monitory są przykładem strukturalnego mechanizmu synchronizacji. Monitor może być rozumiany jako klasa, której wszystkie atrybuty są dostępne wyłącznie z poziomu metod klasowych, a same metody stanowią sekcję krytyczną. Po rozpoczęciu wykonywania metody przez dany wątek/proces, po jego wywłaszczeniu żaden inny wątek nie może rozpocząć wykonywania jakiejkolwiek metody klasy monitora. Wszystkie wątki/procesy próbujące wykonać metodę są umieszczane w kolejce FIFO skojarzonej z danym monitorem. Własności monitora gwarantowane są przez język programowania. Programista zwolniony jest z konieczności jawnego zakładania i zwalniania blokad (np. podnoszenie i opuszczanie semafora). Po opuszczeniu monitora przez wątek do monitora wchodzi wątek czekający najdłużej w skojarzonej z monitorem kolejce FIFO. Monitory dają dużą wygodę programowania i stanowią popularny mechanizm synchronizacji w przypadku obiektowych języków programowania (np. Java) 21

Monitory c.d. Pytanie: Jak zapewnić wzajemne wykluczanie na poziomie języka? Przez dodanie w fazie kompilacji do kodu monitora semafora lub innego obiektu gwarantującego synchronizację. W takim przypadku każda metoda monitora jest chroniona przez ten sam obiekt synchronizujący. Efekt: wykonanie dowolnej metody przez jeden wątek wyklucza możliwość wykonania tej samej lub dowolnej innej metody monitora przez inny wątek Z definicji monitora wynika, że metody monitora wykonywane są jako sekcja krytyczna. Wynika z tego, że synchronizacja za pomocą monitora w przypadku pewnych problemów (jakich?) może sprowadzać się do umieszczenia zmiennych współdzielonych przez wątki wewnątrz monitora. W ten sposób zagwarantowany zostaje wyłączny dostęp do zmiennych współdzielonych 22

Monitory. Wzajemne wykluczanie Realizacja wzajemnego wykluczania przy użyciu monitora wynika wprost z jego definicji. Dla zapewnienia wyłącznego dostępu do zasobu współdzielonego przez jeden proces kod realizujący operacje na zasobie należy umieścić w procedurze monitorowej. Przedstawione rozwiązanie jest poprawne wyłącznie w przypadku, gdy jednocześnie w sekcji krytycznej może przebywać co najwyżej jeden proces. Problemy, w których sekcję krytyczną może jednocześnie wykonywać więcej niż jeden wątek wymagają, by operacje wykonywane na zasobie współdzielonym zostały przeniesione poza monitor; operacje takie nie mogą stanowić fragmentu procedury monitorowej. W odróżnieniu od semaforów programista jest zwolniony z konieczności bezpośredniego oczekiwania i sygnalizowania dostępu do sekcji krytycznej. 23

Monitory. Wewnętrzne kolejki procesów Wewnątrz monitorów dostępny jest specjalny typ zmiennych, tzw. zmienne warunkowe (condition), które w rzeczywistości działają jak wewnętrzne kolejki procesów stosowane do zawieszania i reaktywowania procesów wykorzystujących monitor. Kolejki procesów związane ze zmiennymi warunkowymi są niezależne od kolejki wejściowej monitora. W ogólności możliwe jest zdefiniowanie dowolnej liczby kolejek condition, podczas gdy istnieje tylko jedna kolejka wejściowa monitora. Wewnętrzne kolejki procesów wykorzystywane są do rozwiązania sytuacji, w których proces po wejściu do monitora nie może kontynuować swojej pracy ze względu na brak spełnienia określonych warunków, np. brak dostępu do pewnych zasobów lub zakończenie przetwarzania przez inne procesy. Z definicji monitora (wzajemne wykluczanie) wynika, że proces zajmujący monitor i oczekujący na spełnienie określonych warunków w ogólności powinien zwolnić monitor umożliwiając jego zajęcie przez inny proces. Pytanie: do jakiej niepożądanej sytuacji mogłoby doprowadzić przebywanie procesu w monitorze? 24

Monitory. Wewnętrzne kolejki procesów c.d. Na zmiennych warunkowych condition możliwe jest wykonanie następujących operacji: wait(c) powoduje wstrzymanie (zawieszenie) procesu wywołującego. Proces zostaje wstawiony do kolejki procesów FIFO i na określony czas zwalnia monitor. Do monitora może wejść inny proces oczekujący w kolejce wejściowej monitora. signal(c) powoduje wznowienie (obudzenie, reaktywację) pierwszego (najdłużej oczekującego) procesu z kolejki związanej ze zmienną warunkową c. Wywołanie operacji signal służy zasygnalizowaniu spełnienia warunku, na który mogą oczekiwać inne procesy. Reaktywowany proces wznawia swoje działanie począwszy od pierwszej instrukcji po instrukcji wait(c), która spowodowała jego zawieszenie. Zgodnie z klasyczną definicją monitora proces, który wywołuje funkcję signal natychmiast zwalnia monitor i trafia na pierwszą pozycję kolejki wejściowej monitora (operacja jest niezgodna z typem FIFO kolejki) lub na stos. Konkretne implementacje monitorów przyjmują jednak różne rozwiązania. empty(c) test logiczny na kolejce procesów. Wynik pozytywny (true), gdy kolejka procesów jest pusta, w przeciwnym wypadku wynik negatywny (false) 25

Monitory. Wewnętrzne kolejki procesów c.d. Zgodnie z definicją kolejki procesów zmiennej warunkowej proces wykonujący operację wait zwalnia monitor. Przeciwne rozwiązanie mogłoby doprowadzić do zakleszczenia (blokady) systemu: jeden proces oczekuje na spełnienie warunku (ten który wywołuje wait), ale inny proces, który może zasygnalizować spełnienie warunku nie może wejść do monitora zajętego przez pierwszy proces. Pytanie: Czy proces, który sygnalizuje spełnienie warunku musi wejść do monitora? Tak, ponieważ kolejka procesów obsługiwana przez wait/signal jest wewnętrzną strukturą monitora. W ogólności możliwa jest sytuacja, w której podczas wywoływania operacji signal przez jeden proces, na wejście do monitora czekają procesy zawieszone w kolejce wejściowej monitora oraz procesy zawieszone w kolejce wewnętrznej (związanej ze zmienną warunkową). Zgodnie z klasyczną definicją monitora procesy oczekujące w kolejce wewnętrznej mają pierwszeństwo wejścia do monitora przed procesami w kolejce wejściowej. W praktyce istnieją różne rozwiązania takiego zagadnienia. 26

Monitory. Symulacja semafora ogólnego. Z semaforem ogólnym związana jest zmienna całkowitoliczbowa oraz dwie operacje: wait (opuszczanie semafora) oraz signal (podnoszenie semafora). Uwaga: zgodnie z klasyczną definicją semafora operacja podnoszenia semafora wznawia jeden z procesów oczekujących. W powyższym przykładzie wznawiany jest zawsze proces najdłużej oczekujący (pierwszy w kolejce FIFO). 27

Monitory. Problem producentów i konsumentów 28

Monitory. Problem producentów i konsumentów c.d. W powyższym rozwiązaniu problemu zmienna współdzielona (bufor) jest zamknięta wewnątrz monitora. Gwarantuje to wyłączny dostęp dla każdego z procesów niezależnie Operacje wstawiania i pobierania z bufora stanowią sekcję krytyczną. Wywołania funkcji nie są dodatkowo otaczane kodem wyznaczającym sekcję krytyczną. Sekcja krytyczna wynika z definicji monitora W przypadku zapełnionego bufora każdy producent, który chce umieścić w nim porcję danych jest wstrzymywany i umieszczony w kolejce procesów producenci. W przypadku bufora pustego każdy konsument jest umieszczany w kolejce konsumenci. 29

Monitory. Problem czytelników i pisarzy. Rozwiązanie z możliwością zagłodzenia pisarzy (wariant 1) 30

Monitory. Problem czytelników i pisarzy c.d. Przedstawione rozwiązanie nie posiada własności żywotności: Pisarz, który chce wejść do czytelni musi poczekać na zwolnienie czytelni przez wszystkich czytelników. Czytelnik może wejść do czytelni zawsze, o ile tylko czytelnia jest pusta lub zajęta przez innych czytelników. Może dojść do sytuacji, gdy czytelnia będzie zawsze zajęta przez wciąż dołączających czytelników. Procedury monitora służą do synchronizacji dostępu do czytelni. Same procesy czytania i pisania nie są i nie mogą być zaimplementowane jako operacje wewnątrz monitora. Pisarz otrzymuje dostęp do czytelni po jej zwolnieniu przez ostatniego z czytelników. Wychodzący pisarz budzi pierwszego z oczekujących czytelników. Jeśli kolejka czytelników jest pusta do monitora może wejść kolejny pisarz. Pierwszy z czytelników obudzonych przez pisarza wyzwala kaskadę czytelników. Odpowiada za to wiersz 3 procedury czytelnik_in Uwaga: Operacja signal wykonana na pustej kolejce procesów nie daje żadnego efektu 31

Monitory. Problem czytelników i pisarzy c.d. Rozwiązanie z możliwością zagłodzenia pisarzy (wariant 2) W przypadku niepustej kolejki czytelników wychodzący pisarz w pętli repeat wybudza kolejnych czytelników: Po każdym wywołaniu signal pisarz zwalnia monitor na rzecz wchodzącego czytelnika. Czytelnik po wykonaniu procedury czytelnik_in zwalnia monitor, który ponownie zostaje zajęty przez pisarza. 32

Monitory. Problem czytelników i pisarzy c.d. Rozwiązanie poprawne (bez możliwości zagłodzenia) 33

Programowanie wielowątkowe w Javie (krótka dygresja) W celu uruchomienia zadania w odrębnym wątku należy 1. Kod zadania umieścić w ciele metody run klasy implementującej interfejs Runnable class FooRunnable implements Runnable { } public void run() { } //funkcjonalność wątku 2. Utworzyć obiekt powyższej klasy: Runnable r = new FooRunnable() 3. Utworzyć obiekt klasy Thread przekazując obiekt klasy Runnable jako argument konstruktora: Thread t = new Thread(r) 4. Wywołać metodę start na obiekcie klasy Thread. Uwaga: Bezpośrednie wywołanie metody run z obiektu Thread lub Runnable nie powoduje utworzenia nowego wątku, a wyłącznie wywołanie kodu metody w wątku wywołującym 34

Synchronizacja w Javie W Javie obiekt dowolnej klasy może być monitorem. Wystarczy, by metody klasy posiadały specyfikator synchronized, a atrybuty były prywatne. Przykład: Wzajemne wykluczanie jest w tym przypadku gwarantowane przez język: wejście do monitora jednego procesu wyklucza możliwość wejścia do niego innych procesów. 35

Synchronizacja w Javie c.d. W Javie monitory posiadają następujące własności: Monitorem jest klasa posiadająca wyłącznie pola prywatne Z każdym obiektem klasy (monitora) związana jest blokada. Blokada jest obiektem klasy działającej jak muteks (mutex, mutual exclusion), np. klasy Lock. Blokada taka nie jest dostępna bezpośrednio dla programisty. Wywołanie metody synchronizowanej obiektu powoduje zajęcie przez wątek blokady wewnętrznej związanej z danym obiektem (tym obiektem na rzecz, którego metoda jest wywoływana). Wszystkie metody synchronizowane obiektu są blokowane na blokadzie wewnętrznej, tzn. blokada założona w związku z wywołaniem dowolnej metody blokuje możliwość wywołania dowolnej innej metody synchronizowanej obiektu (nie klasy!) Blokada jest automatycznie zwalniana po wykonaniu metody synchronizowanej Wątek zajmuje blokadę poziomu obiektu, gdy rozpoczyna wykonywanie metody synchronizowanej obiektu. W przypadku, gdy rozpoczyna wykonywanie metody statycznej zajmuje blokadę na poziomie całej klasy Blokady mogą być wielowejściowe 36

Synchronizacja w Javie c.d. Poza tworzeniem metod synchronizowanych możliwe jest wykorzystanie bloków synchronizowanych. Bloki synchronizowane są użyteczne w przypadku konieczności synchronizacji dostępu do już istniejących obiektów, których nie można uzupełnić o dodatkowe, synchronizowane metody. Tworzenie metod synchronizowanych ma sens tylko wówczas, gdy pożądanym efektem jest wyłączne wykonanie całej metody na obiekcie. W przypadku, gdy konieczna jest synchronizacja tylko fragmentu metody należy wykorzystać blok synchronized. Przykład: W Javie nie są dostępne synchronizowane zmienne. Efekt można jednak uzyskać przez bloki synchronized. 37

Synchronizacja w Javie c.d. Preferowanym sposobem zapewnienia wzajemnego wykluczania jest wykorzystanie bloków synchronizowanych, a nie synchronizowanych metod: sekcja krytyczna bloku jest mniejsza niż metody. Ze względów efektywnościowych sekcje krytyczne powinny być tak krótkie, jak to tylko możliwe. 38

Przykład. Synchronizacja w Javie c.d. Blokada 39

Blokady wielowejściowe w Javie W Java SE 5.0 w pakiecie java.util.concurrent wprowadzona została klasa blokady wielowejściowe ReentrantLock. Wielowejściowość blokady sprowadza się do możliwości wielokrotnego zamknięcia blokady przez wątek, który posiada już blokadę. Blokada wielowejściowa posiada licznik przechowujący liczbę wywołań metody lock na obiekcie blokady. Zwolnienie blokady przez wątek wymaga wielokrotnego wywołania metody unlock (tyle razy ile razy została wykonana metoda lock). Blokady wielowejściowe pozwalają na wywoływanie przez jeden wątek różnych metod, które korzystają z tej samej blokady. Wywołanie takiej metody przez inny wątek (który nie ma na własność blokady) powoduje zawieszenie wątku wywołującego. 40

Metody notify, notifyall oraz wait Metody notify, notifyall oraz wait zdefiniowane są w klasie java.lang.object. Ponieważ każdy obiekt w javie jest wyprowadzony z klasy dziedziczącej z Object, metody dostępne są dla każdego obiektu. Metody są wykorzystywane do synchronizacji dostępu do wspólnych zasobów http://docs.oracle.com/javase/6/docs/api/java/lang/object.html W Javie każdy obiekt posiada wewnętrzną blokadę (internal/intrinsic /monitor lock). Operacje wait, notify oraz notifyall są operacjami związanymi z blokadą wewnętrzną (inaczej: monitorem obiektu) Monitor obiektu jest zajmowany przez wątek po wejściu do bloku lub metody synchronizowanej. Z definicji, żaden inny obiekt nie może zająć monitora obiektu, zanim nie zostanie on zwolniony przez poprzedni wątek (wzajemne wykluczanie) Wywołania powyższych metod mogą następować wyłącznie z kodu synchronizowanego Wątek próbujący zająć zajęty monitor jest blokowany wait() zwalnia monitor obiektu. Wątek wywołujący umieszczany jest w wewnętrznej kolejce wątków oczekujących na spełnienie warunku. Uwaga: program, w którym istnieją wątki wywołujące wait(), ale brak jest wątków wywołujących notify()/notifyall() jest niepoprawny 41

Metody notify, notifyall oraz wait c.d. notify() wybudza jeden z wątków oczekujących w wewnętrznej kolejce związanej z monitorem obiektu. Gdy na wybudzenie czeka więcej niż jeden wątek, wybór jednego z nich jest arbitralny nie ma możliwości wskazania, który z oczekujących wątków powinien zostać wybudzony notifyall() wybudza wszystkie wątki oczekujące w kolejce wewnętrznej monitora obiektu (wszystkie wątki przechodzą do stanu RUNNABLE). Planer/scheduler określa kiedy oraz który z wybudzonych wątków zostanie wznowiony. Potencjalne problemy? notifyall() może powodować większe obciążenie systemu niż notify(). Dlaczego? Operacje powiadamiania nie mają efektu, gdy kolejka wątków oczekujących na monitorze obiektu jest pusta Każdy obiekt w Javie odpowiada monitorowi z dokładnie jedną zmienną warunkową (obiektem warunku). Dlaczego? W ogólności w klasycznym monitorze możliwe jest stworzenie dowolnej liczby zmiennych warunkowych 42

Metody notify, notifyall oraz wait c.d. Wywołanie operacji wait() przez dany wątek powinno być poprzedzone sprawdzeniem warunku w pętli while zamiast za pomocą instrukcji if: Wynika z faktu, że zablokowany wcześniej wątek (po wykonaniu wait) nie wznawia swojej pracy natychmiast po otrzymaniu powiadomienia. W czasie pomiędzy otrzymaniem powiadomienia, a wznowieniem pracy warunek może ulec zmianie Niepoprawne wykorzystanie metody notify() zamiast notifyall() może doprowadzić do niepoprawnego funkcjonowania programu współbieżnego (brak żywnotności: zakleszczenia). Zaleca się wykorzystywanie funkcji notifyall() zamiast notify() Scenariusz, w którym wykorzystanie notify() ma przewagę nad notifyall() zachodzi, gdy wszystkie funkcjonujące w systemie wątki realizują identyczne zadanie, (worker threads) a to który z nich zostanie wybrany w danym momencie jest pozbawione znaczenia 43

Metody notify, notifyall oraz wait c.d. Przykład zakleszczenia wywołanego wykorzystaniem notify() zamiast notifyall(): 1. W systemie funkcjonuje dwóch producentów i dwóch konsumentów 2. System znajduje się w stanie, w którym zablokowane są konsumenty oraz jeden z producentów 3. Bufor współdzielony posiada jedno wolne miejsce 4. Rozpoczyna wykonywanie wątek producenta. Wstawia element i wywołuje metodę notify() 5. Ponieważ notify() nie wskazuje konkretnego wątku do wybudzenia, planer podejmuje arbitralną decyzję o wznowieniu drugiego z producentów 6. Producent identyfikuje spełnienie warunku wymagającego wywołanie wait() 7. Jedynym z wątków który może zostać uruchomiony jest wątek producenta, który wykonuje operację wait() 8. Ostatecznie w puli wątków zablokowanych (oczekujących na spełnienie warunku) znajdują się wszystkie wątki. ZAKLESZCZENIE. Żaden z wątków nie wywoła metody notify(). Rozwiązaniem problemu byłoby wykorzystanie notifyall() zamiast notify(). 44 Dlaczego?

Obiekty blokad i obiekty warunków Przykład: problem producentów i konsumentów. Konstrukcje synchronizowane za pomocą słowa kluczowego synchronized dają tylko jedną wewnętrzną kolejkę wątków oczekujących. Wywołanie metody notifyall() aktywuje wszystkie wątki dezaktywowane instrukcją wait. Jest to rozwiązanie nieefektywne (wolne) Do zarządzania wątkami, które po wejściu do sekcji krytycznej wykrywają sytuację braku możliwości kontynuacji swojej pracy służą obiekty warunków (zmienne warunkowe) Obiekt warunku o(bok obiektu blokady) tworzony jest automatycznie, gdy w kodzie zostanie zdefiniowany blok za pomocą słowa kluczowego synchronized. Programista nie ma jednak bezpośredniego dostępu do obiektów blokady i warunku Bezpośrednie tworzenie obiektów warunków (Condition) umożliwia skojarzenie z jedną blokadą dowolnej liczby niezależnych obiektów warunków Tworzenie obiektów warunków 45

Obiekty blokad i obiekty warunków c.d. Metody obiektu warunku: await wywoływana na obiekcie warunku, po zidentyfikowaniu sytuacji braku możliwości kontynuowania pracy. Wątek wywołujący metodę zostaje dezaktywowany i umieszczony w kolejce wątków oczekujących na spełnienie warunku, a blokada skojarzona z warunkiem (blokada, z której warunek został wyprowadzony) zostaje zwolniona. To umożliwia działanie wątkom oczekującym na zajęcie blokady. Wątek wywołujący tę metodę nie może reaktywować samego siebie signalall powoduje reaktywację wszystkich wątków oczekujących na warunek. Wątki reaktywowane zmieniają swój status na RUNNABLE (wykonywalny). Nie jest to jednak równoważne z bezwarunkowym wznowieniem ich pracy. Wątki trafiają do puli wątków, z których wybiera algorytm planujący (scheduler). Po wznowieniu pracy przez wątek kontynuuje on pracę od punktu, w którym ją przerwał wywołując metodę await signal metoda odblokowuje jeden, losowo wybrany wątek. Jest to mniej obciążające niż odblokowanie wszystkich oczekujących wątków, ale może doprowadzić do sytuacji braku żywotności (zakleszczenie) 46

Obiekty blokad i obiekty warunków c.d. Metoda await powinna być wywoływana w pętli następującej postaci Wątek wznawiający swoje działanie na skutek wywołania metod signal lub signalall powinien ponownie sprawdzić spełnienie warunku. Nie ma gwarancji, że w momencie wznowienia pracy przez wątek warunek jest nadal spełniony. Wynika to z tego, że pomiędzy zasygnalizowaniem spełnienie warunku przez jeden wątek, a wznowieniem pracy przez drugi swoje działania mogły wykonać inne wątki, które potencjalnie mogły zmienić stan spełnienia warunku Metody wait, signal oraz signalall klasy Condition są odpowiednikami metod wait, notify oraz notifyall klasy Object skojarzonych z wbudowanym warunkiem Blokady a warunki: Warto zauważyć, że blokady chronią blok kodu, pozwalając wykonywać go w danym czasie tylko jednemu wątkowi. Blokady zarządzają przy tym wątkami, które próbują wejść do sekcji krytycznej. Obiekty warunkowe (Condition) zarządzają wątkami, które weszły do sekcji krytycznej kodu, ale które nie mogą kontynuować działania. Zarządzanie polega w tym miejscu na dezaktywowaniu oraz aktywowaniu wątków 47

Obiekty blokad i obiekty warunków c.d. Pomiędzy wątkiem, który oczekuje na blokadę (wykonanie metody lock na obiekcie blokady wielowejściowej), a wątkiem, który wywołuje metodę await, istnieje zasadnicza różnica. Drugi z nich jest umieszczany w kolejce wątków oczekujących warunku (wait set). Wątek taki nie przechodzi w stan wykonywalności, dopóki inny wątek nie wywoła metody signalall na rzecz tego samego warunku Metody lock() i await() wykonywane odpowiednio na obiektach blokad lub warunków powodują, że wątek, który wywoła taką metodę w celu uzyskania blokady będącej w posiadaniu innego wątku, zostaje zablokowany na nieokreśloną ilość czasu. Istnieją wersje takich metod, które nie blokują wątku lub blokują go na co najwyżej określony z góry interwał czasu. Przykład: metoda trylock() wywoływana na obiekcie blokady próbuje założyć blokadę i jeśli jest to możliwe (blokada nie jest zajęta przez inny wątek) zwraca wartość logiczną true. W przeciwnym wypadku zwraca wartość false, a wątek wywołujący nie jest blokowany i może wykonać inne działania. Metoda trylock może być wywołana z parametrem czasowym określającym limit górny czasu blokowania w przypadku, gdy blokada jest zajęta przez inny wątek. 48

Stany wątków w Javie W Javie wątek może znajdować się w jednym z sześciu możliwych stanów: NEW (nowy) wątek utworzony za pomocą operatora new na przykład new Thread() nie jest automatycznie uruchamiany, ale znajduje się w stanie NEW. Do uruchomienia konieczne jest wywołanie metody start() wątku. Stan NEW odpowiada sytuacji, gdy program nie rozpoczął jeszcze wykonywania kodu wątku RUNNABLE (wykonywalny) jest to stan, w który wątek zostaje przeniesiony po wywołaniu metody start(). Wątek taki może, ale nie musi zostać uruchomiony. Ważne jest, że potencjalnie MOŻE zostać uruchomiony. W Javie nie został wprowadzony niezależny stan reprezentujący wykonywanie wątku (stąd nazwa stanu runnable). Przydział czasu dla wątku (jego uruchomienie lub ponowne wznowienie) leży w gestii systemu operacyjnego (podsystemu planowania, schedulera). Wątek, który zostaje uruchomiony, nie musi działać w sposób ciągły aż do wykonania ostatniej instrukcji ciała wątku. Większość nowoczesnych systemów operacyjnych stosuje planowanie wywłaszczające: zarządca przyznaje wątkowi ściśle określony kwant czasu, po upływie którego wątek musi zawiesić swoje wykonywanie na rzecz innego wątku. (Istnieją systemy i JVM, które nie wprowadzają wywłaszczania: wątek po rozpoczęciu wykonywania może się wykonywać nieprzerwanie aż do ostatniej instrukcji) 49

Stany wątków w Javie c.d. BLOCKED wątek wprowadzany jest w stan BLOCKED, gdy usiłuje założyć blokadę wewnętrzną na obiekt w dyspozycji innego wątku (np. próbuje wykonać blok lub metodę synchronizowaną wykonywaną przez inny wątek). WAITING stan jest wyzwalany przez wywołanie przez wątek metody Object.wait, Thread.join, oczekiwanie na obiekt klasy Lock (wywołanie metody lock na obiekcie zamka w zajętego przez inny obiekt) lub Condition. W stanach BLOCKED i WAITING wątki są okresowo nieaktywne, nie wykonują żadnego kodu i zużywają minimalne ilości zasobów (oczekiwanie pasywne). Decyzja o reaktywacji wątku należy do planera (zarządcy). TIMED WAITING stan wątku utrzymuje się co najmniej przez czas określony przez argument metod wyzwalających taki stan lub do odebrania odpowiedniego powiadomienia. Stan jest wyzwalany przez metody Thread.sleep oraz czasowe wersje metod Object.wait, Thread.join, Lock.tryLock oraz Condition.await TERMINATED wątek może zostać zamknięty na jeden z dwóch sposobów: 1. wraz z wykonaniem ostatniej instrukcji metody run; 2. z powodu nieprzechwyconego wyjątku, który kończy metodę run http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/thread.state.html 50

Stany wątków w Javie c.d. Non-existing create thread object destroy New start wait, join Blocked Runnable destroy notify, notifyall run method thread termination exits Terminated (Dead) destroy garbage collected Non-Existing and finalization 51

Priorytety wątków i szeregowanie Każdy wątek posiada ustalony priorytet określony liczbą z zakresu 1..10 (określone przez pola statyczne klasy Thread: Thread.MIN_PRIORITY oraz Thread.MAX_PRIORITY) Domyślnie wątek dziedziczy priorytet po wątku, w którym został utworzony Do ustalenia priorytetu wątku służy metoda setpriority (final void setpriority(int level)) Aktualną wartość priorytetu wątku można uzyskać przez wywołanie metody getpriority (final int getpriority()) Algorytm szeregujący/planujący ustala kolejność wykonywania wątków na podstawie priorytetów wątku (w ogólności pierwszeństwo wykonania ma wątek o najwyższym priorytecie) W każdym momencie, spośród wątków w stanie RUNNABLE wybierany jest ten o najwyższym priorytecie W większości systemów jest implementowany podział czasu (time-slicing; wątki są wywłaszczane po upływie kwantu czasu) Wykonywany wątek może być wywłaszczony, jeśli pojawi się wątek o wyższym priorytecie w stanie RUNNABLE (i aktywne jest planowanie z wywłaszczaniem) 52

Priorytety wątków i szeregowanie c.d. W ogólności Java nie daje gwarancji o stosowanych algorytmach szeregowania, o implementacji wywłaszczania, etc. Aspekty te zależą od konkretnej implementacji JVM Można założyć, że najczęściej zasada wywłaszczania nie obowiązuje w systemach operacyjnych urządzeń przenośnych i systemów wbudowanych (telefony, urządzenia AGD, etc.) W takim przypadku stosowane jest planowanie kooperacyjne Planowanie kooperacyjne wykorzystywane zostało m. in. w systemach Windows 3.x. Polega ono na dobrowolnym oddawaniu kontroli przez wątki (wielozadaniowość oparta na współpracy/kooperacji). Problem: pojedynczy źle zaimplementowany lub wrogi proces potrafi przejąć kontrolę na procesorem i zdestabilizować pracę całego systemu Zachowanie planera nie jest gwarantowane (przewidywalne) w przypadku, gdy wszystkie wątki w puli mają identyczne priorytety lub wątek aktualnie wykonywany ma priorytet identyczny z priorytetem wątków w puli wątków runnable. W takim przypadku wątek wykonywany może być wykonywany aż do ostatniej instrukcji lub wywłaszczony na rzecz dowolnego innego wątku w puli 53

Priorytety wątków i szeregowanie c.d. Większość implementacji maszyn wirtualnych (JVM) mapuje wątki Javy na wątki natywne systemu operacyjnego. W takim przypadku priorytety wątków są mapowane na priorytety właściwe dla systemu, który może implementować większą lub mniejszą liczbę poziomów priorytetów. Przykład: W systemie Windows wyróżnia się siedem poziomów priorytetów, tym samym niektóre z priorytetów Javy zostają zmapowane na identyczny poziom priorytetów systemowych. W implementacji JVM Sun dla systemów Linuxowych priorytety wątków są ignorowane wszystkie wątki mają ten sam priorytet. W praktyce program wielowątkowy jest niepoprawny jeśli warunkiem jego poprawnego wykonania jest wykonanie wątków w ściśle określonej sekwencji Na decyzje planera wpływa wywołanie następujących metod (dostępnych bezpośrednio dla programisty) 54

Priorytety wątków i szeregowanie. Przykłady Sleep gwarantuje naprzemienne wykonywanie wątków Po wywołaniu metody sleep wątkowi odbierany jest czas procesora na co najmniej czas określony w argumencie metody. Nie ma jednak gwarancji wznowienia pracy wątku po upłynięciu dokładnie takiego czasu 55

Priorytety wątków i szeregowanie. Przykłady c.d. Wątek tworzony w ciele metody main ma priorytet identyczny z priorytetem wątku głównego Metoda yield w zamyśle ma służyć do zrzeczenia się czasu procesora przez wątek wywołujący na rzecz innego wątku o identycznej wartości priorytetu. Zachowanie wątku po wywołaniu metody nie jest jednak gwarantowane. Możliwa jest sytuacja, w której po wywołaniu metody planer przydzieli czas procesora wątkowi wołającemu, który zrzekł się czasu. 56

Priorytety wątków i szeregowanie. Przykłady c.d. W systemach z podziałem czasu i wywłaszczaniem efektem wykonania programu będzie naprzemienne drukowanie Foo oraz Bar. W systemach bez podziału czasu wątek Foo przejmuje kontrolę nad procesorem i doprowadzi do zagłodzenia drugiego z wątków. 57

Blokady odczytu-zapisu Blokady odczytu-zapisu (ReentrantReadWriteLock), w odróżnieniu od standardowych blokad wielowejściowych (ReentrantLock) gwarantują dostęp do sekcji krytycznej wielu wątkom czytającym i tylko jednemu wątkowi piszącemu Tworzenie blokad zapisu i odczytu Powyższe blokady wykorzystuje się w metodach dostępowych Blokadę odczytu może zakładać wiele wątków odczytujących, ale żaden zapisujący. W ten sposób można uzyskać efekt wielodostępu 58

Synchronizatory W pakiecie java.util.concurrent znajduje się kilka klas, które ułatwiają zarządzanie typowymi scenariuszami akcji współbieżnych Rodzaj synchronizatorów: 1. Semafory klasa Semaphore odpowiada klasycznemu semaforowi (binarnemu lub ogólnegmu). Odpowiednikami klasycznych instrukcji semaforowych wait oraz signal są metody acquire oraz release. Semafory służą do ograniczenia liczby wątków mających dostęp do zasobu. Dostęp do zasobu otrzymuje tylko wątek, który wcześniej uzyskał zezwolenie. Semafor przechowuje licznik zezwoleń 59

Synchronizatory c.d. 2. Bariera pozwala zdefiniować punkt w programie (barierę), na którym wątek wstrzymuje swoją pracę aż do dotarcia do tego punktu innych wątków. W praktyce barierę wykorzystuje się w sytuacji istnienia wielu wątków dostarczających wyniki cząstkowe. Kiedy jeden wątek zakończy swoje zadanie, zatrzymuje się na barierze. Kiedy wszystkie wątki dotrą do bariery zostaje ona otwarta i wątki mogą kontynuować pracę. Wykorzystanie bariery (argument konstruktora określa liczbę wątków biorących udział w zadaniu): Możliwe jest opcjonalne wskazanie domyślnej akcji jaka zostanie wykonana przez barierę, gdy wszystkie wątki skojarzone z barierą do niej dotrą 60

Egzekutory i pule wątków Pule wątków do rozwiązanie stosowane w celu: 1. ograniczenia liczby jednocześnie funkcjonujących w ramach danej aplikacji wątków, 2. ograniczenia obciążenia systemu operacyjnego wynikającego z konieczności tworzenia nowych wątków (ograniczenie narzutu tworzenia nowych wątków) Pule wątków zawierają pewną liczbę nieaktywnych wątków, które są gotowe do działania (worker threads). Przekazanie do puli obiektu implementującego interfejs Runnable powoduje wykonanie przez jeden z wątków puli metody run takiego obiektu. Po zakończeniu działania metody wątek nie zostaje zakończony, ale przechodzi w stan oczekiwania na kolejne zadanie Klasa Executors definiuje statyczne metody służące do tworzenia puli wątków. Wszystkie podane niżej metody zwracają egzekutora obiekt klasy ThreadPoolExecutor: 1. newcachedthreadpool pula bez ustalonej liczby wątków. Wątki tworzone są dynamicznie, gdy wątki wcześniej utworzone nie wystarczają do wykonania zleconych zadań. Nieaktywne wątki są przetrzymywane przez 60 sekund. Egzekutor nie kolejkuje zadań tworzy je na żądanie. Istnieje ryzyko, że ciągłe zlecanie 61 nowych zadań do wykonania spowoduje powstanie dużej liczby wątków

Egzekutory i pule wątków c.d. 2. newfixedthreadpool pula zawierająca ustaloną z góry, określoną jako argument, liczbę wątków. Egzekutor tego typu wykonuje zadania za pomocą określonej liczby wątków. Nieaktywne wątki są zachowywane bezterminowo. Gdy liczba zadań do wykonania przekracza liczbę wątków w puli, zadania są kolejkowane i wykonywane po zakończeniu wcześniejszych 3. newsinglethreadexecutor pula składająca się z jednego wątku wykonującego zadania po kolei (egzekutor realizuje zadania za pomocą jednego wątku). Gdy jedyny wątek jest zajęty, kolejne są kolejkowane i wykonywane jeden po drugim Obiekt Runnable można przekazać do egzekutora za pomocą metody submit Egzekutor jest zamykany za pomocą metody shutdown. Zamykanie egzekutora powoduje zablokowanie możliwości przyjmowania nowych zadań do wykonania. Po zakończeniu wszystkich zadań wątki puli zostają zakończone (terminated). Metoda shutdownnow powoduje, że pula kończy wszystkie wątki nie wykonujące aktualnie zadań oraz próbuje przerwać aktualnie uruchomione 62