Teoria współbieżności - Laboratorium
Programowanie współbieżne - wątki 1
Wątki
Cztery typy programowania wielowątkowego:
- Niezależne wątki. Najprostszy model: wątki niepowiązane ze sobą. Mechanizmy programistyczne: podstawowe abstrakcje do tworzenia wątków.
- Powiązane, niesynchronizowane wątki. Wątki powiązane ze sobą, jednak nie oddziałują na siebie i nie posiadają danych współdzielonych. Np. problem podzielony na podproblemy, z których każdy przetwarzany jest przez oddzielny wątek. Mechanizmy programistyczne: pule wątków.
- Wątki wzajemnie wykluczające się. Wątki operują na współdzielonych danych i muszą być synchronizowane. Np. wątki czytające i modyfikujące stan zmiennej. Mechanizmy programistyczne: synchronizacja wątków (semafory, blokady etc.)
- Komunikujące się, wzajemnie wykluczające wątki. Wątki operują na współdzielonych danych, ale również komunikują się / koordynują działania. Np. zależność w stylu producent-konsument. Mechanizmy programistyczne: koordynacja typu wait/notify, zmienne warunkowe.
Wątki w języku Java
- Wbudowane w język
- Dwa rodzaje implementacji
- Przez dziedziczenie z klasy Thread
Klasa:
class MyThread extends Thread {
. . .
public void run() {
. . .
}
}
Tworzenie obiektu i uruchamianie wątku:
MyThread t = new MyThread();
t.start();
- Przez implementację interfejsu Runnable
Klasa:
class MyThreadR implements Runnable {
. . .
public void run() {
. . .
}
}
Tworzenie i uruchamianie:
MyThreadR r = new MyThreadR();
Thread t = new Thread(r);
t.start();
- Metoda run()
public void run() {
// kod wątku
}
- Klasa Thread
- Niektore wazne metody
void setName(String name)
String getName()
void setPriority(int newPriority)
int getPriority()
void join()
static void sleep(long milis, int nanos)
public static Thread currentThread()
String toString()
Wątki w JVM
Wyścig
- Zjawisko wyścigu (race condition) występuje gdy wątki współbieżnie korzystają z zasobu dzielonego (np. zmiennej), przy czym przynajmniej jeden z nich zmienia stan tego zasobu.
- Wyścig często jest przyczyną niedeterministycznego zachowania się programu i może prowadzić do trudnych do wykrycia błędów.
- Pojęcie thread-safety (bezpieczeństwo dla wątków, wielobieżność): kod jest bezpieczny dla wątków, gdy jego współbieżne wykonanie nie powoduje sytuacji wyścigu.
Zadanie 1
Zaimplementować program, w którym działają dwa wątki posiadające dostęp do wspólnego obiektu
Counter, na którym można wykonać dwie operacje:
inc i
dec (zwiększenie/zmniejszenie stanu o 1, stan początkowy = 0). Jeden wątek cały czas inkrementuje licznik, drugi dekrementuje, oba robią to w pętli 1e9 razy. Na końcu (po zakończeniu działania obu wątków) program wypisuje końcowy stan licznika.
Zadanie 2
W systemie dziala N wątkow, które dzielą obiekt licznika (początkowy stan licznika = 0). Każdy wątek wykonuje w pętli 5 razy inkrementację licznika. Zakładamy, że inkrementacja składa się z sekwencji trzech instrukcji: read, inc, write (odczyt z pamięci, zwiększenie o 1, zapis do pamięci). Wątki nie są synchronizowane.
- Jaka jest teoretycznie najmniejsza wartość licznika po zakończeniu działania wszystkich wątków i jaka kolejność instrukcji (przeplot) do niej prowadzi?
- Analogiczne pytanie -- jaka jest maksymalna wartość licznika i odpowiedni przeplot instrukcji?
Bibliografia
- JVM architecture explained
Bartosz Baliś, balis at agh.edu.pl