Podstawy współbieżności - Uniwersytet Ekonomiczny w Krakowie

Transkrypt

Podstawy współbieżności - Uniwersytet Ekonomiczny w Krakowie
2009-12-15
Podstawy współbieżności
Algorytmy i struktury danych.
Wykład 6.
Rok akademicki: 2009/2010
Od koncepcji współbieżności do systemów rozproszonych
• Współbieżnośd – rozważany na poziomie koncepcyjnym
sposób realizacji zadao obliczeniowych dopuszczający
możliwośd jednoczesnego wykonywania więcej niż jednej
czynności.
• Realizacja koncepcji współbieżności:
– systemy z podziałem czasu (w rzeczywistości zadania nie są
realizowane w sposób równoległy; czas pracy procesora dzielony jest
pomiędzy realizowane zadania; jest to praca pozornie równoległa)
– systemy równoległe (pozwalające na rzeczywistą równoległośd):
• maszyny wieloprocesorowe (komunikacja odbywa się za pośrednictwem
pamięci operacyjnej),
• systemy rozproszone (połączone ze sobą komputery współpracujące ze
sobą w celu rozwiązania zadania; komunikacja odbywa się za
pośrednictwem sieci komputerowej).
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
2
1
2009-12-15
Zalety współbieżności
• zwiększenie wydajności (skrócenie czasu realizacji programu):
– w systemach równoległych – jednoczesne wykonywanie wielu zadao
(na różnych procesorach/maszynach)
– w systemach z podziałem czasu – lepsze wykorzystanie zasobów
komputera
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
3
Wady współbieżności
• Zwiększona trudnośd w projektowaniu algorytmów
przetwarzania:
– zaprojektowanie właściwego sposobu podziału zadania na realizowane
równolegle podzadania,
– określenie zasad komunikacji pomiędzy realizowanymi równolegle
wątkami,
– określanie zasad dostępu do współdzielonych danych,
• zwiększone prawdopodobieostwo popełnienia błędów.
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
4
2
2009-12-15
Realizacja koncepcji współbieżności w języku Java
• wątki:
– logicznie wyodrębnione sekwencje instrukcji realizowane w sposób
pozornie równoległy;
– wykorzystują mechanizm podziału czasu;
– realizowane są w obrębie tej samej maszyny wirtualnej;
• programowanie rozproszone (sieciowe):
– komunikujące się ze sobą programy uruchamiane na różnych
komputerach (i różnych maszynach wirtualnych);
– programowanie rozproszone wykorzystuje wielowątkowośd.
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
5
Program jednowątkowy
• Wątek - częśd programu, która może byd realizowana w
sposób współbieżny.
• Program jednowątkowy - składa się z jednej sekwencji
instrukcji /tzw. wątek główny programu/ (w języku Java
tworzą one treśd metody main(…) w klasie bazowej).
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
6
3
2009-12-15
Program wielowątkowy
• Z poziomu wątku głównego tworzone są inne, realizowane
współbieżnie, wątki;
• Każdy wątek może tworzyd kolejne wątki;
• Wątki mogą korzystad ze wspólnych danych;
• Program wielowątkowy kooczy pracę po zrealizowaniu wątku
głównego i wszystkich pozostałych wątków.
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
7
Reprezentacja wątków w języku Java
• Wątek reprezentowany jest przez klasę będącą potomkiem
klasy Thread, której najważniejsze metody to:
– public Thread() - konstruktor obiektu reprezentującego
wątek
– public Thread(String name) - konstruktor
pozwalający nadad nazwę tworzonemu wątkowi
– public void run() - definiuje operacje realizowane w
ramach wątku
– public void start() - wywołuje metodę run()
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
8
4
2009-12-15
Definiowanie wątków za pomocą obiektów klasy Thread i klas
pochodnych
class Gwiazdka extends Thread {
public void run() {
for (int i = 0; i < 10;i++) {
System.out.print("*");
try {
sleep(1000);
}
catch(InterruptedException e) {
}
}
}
}
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
9
.....
class Plus extends Thread {
public void run() {
for (int i = 0; i < 10;i++) {
System.out.print("+");
try {
sleep(1000);
}
catch(InterruptedException e) {
}
}
}
}
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
10
5
2009-12-15
.....
public class TworzenieWatkow1 {
public static void main(String [] args) {
Gwiazdka g = new Gwiazdka();
Plus p = new Plus();
g.start();
p.start();
System.out.print("KONIEC");
}
}
Wyniki działania programu
KONIEC*++**++*+*+*+*+*+**+
Definicja metody sleep (w klasie Thread):
public static void sleep(long millis) throws InterruptedException
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
11
Definiowanie wątku za pomocą klasy implementującej
interfejs Runnable
•
•
•
•
Obliczenia realizowane przez wątek opisane są w klasie implementujacej
interfejs Runnable
Interfejs Runnable definiuje nagłówek jednej metody:
public void run()
metoda ta definiuje operacje realizowane w ramach wątku.
Przedstawiony mechanizm tworzenia wątków należy stosowad wtedy, gdy
klasa reprezentująca wątek jest potomkiem klasy innej niż Thread (np.
klasy Applet) i - z uwagi na jednokrotny charakter dziedziczenia w języku
Java - nie może dziedziczyd cech klasy Thread.
Obiekt klasy implementującej interfejs Runnable należy przekazad jako
parametr konstruktora w trakcie tworzenia obiektu typu Thread.
Uruchomienie wątku następuje za pomocą metody start(), która wywołuje
metodę run().
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
12
6
2009-12-15
Przykład
class Gwiazdka implements Runnable {
public void run() {
for (int i = 0; i < 10;i++) {
System.out.print("*");
try {
Thread.sleep(1000);
}
catch(InterruptedException e) {
}
}
}
}
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
13
.....
class Plus implements Runnable {
public void run() {
for (int i = 0; i < 10;i++) {
System.out.print("+");
try {
Thread.sleep(1000);
}
catch(InterruptedException e) {
}
}
}
}
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
14
7
2009-12-15
.....
public class TworzenieWatkow2 {
public static void main(String [] args)
{
Thread g = new Thread(new Gwiazdka());
Thread p = new Thread(new Plus());
g.start();
p.start();
System.out.print("KONIEC");
}
}
Wyniki działania programu
KONIEC*+*+*+*+*+*+*+*+*+*+
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
15
Korzystanie ze wspólnych zasobów
• Wątki mogą korzystad ze wspólnych zasobów, ale program
powinien sterowad dostępem do współużytkowanych
obiektów.
• Do sterowanie dostępem do wspólnych zasobów służy
mechanizm synchronizacji.
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
16
8
2009-12-15
Korzystanie ze wspólnych zasobów bez mechanizmu
synchronizacji
Przykład programu nie zawierającego mechanizmów synchronizacji wspólnym zasobem jest standardowy strumieo wyjściowy.
class Watek1 implements Runnable {
public void run() {
for (int i = 1; i <= 10; i++) {
try {
Thread.sleep(100);
}
catch (InterruptedException e)
}
System.out.print("A");
}
}
}
{
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
17
.....
class Watek2 implements Runnable {
public void run() {
for (int i = 1; i <= 10; i++) {
try {
Thread.sleep(100);
}
catch(InterruptedException e) {
}
System.out.print("B");
}
}
}
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
18
9
2009-12-15
.....
public class WspolneZasoby {
public static void main(String [] args)
{
Thread w1 = new Thread(new Watek1());
Thread w2 = new Thread(new Watek2());
w1.start();
w2.start();
System.out.println("KONIEC");
}
}
Wynik działania programu:
KONIEC
BABABAABBABABABAABBA
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
19
Sekcja krytyczna wątku
• Sekcja krytyczna wątku - fragment programu (będącego
częścią wątku), z poziomu którego następuje odwołanie do
wspólnego zasobu.
• W danej chwili tylko jeden wątek może realizowad kod
tworzący sekcję krytyczną.
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
20
10
2009-12-15
Schemat sekcji krytycznej
Wątek 1
Wątek 2
sekcja
krytyczna
sekcja
krytyczna
Wspólny
zasób
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
21
Realizacja sekcji krytycznej
• Jeżeli wątek A realizuje swoją sekcję krytyczną, to wątek B, po
dojściu do fragmentu kodu tworzącego jego sekcję krytyczną,
zostanie wstrzymany, aż do chwili zakooczenia realizacji sekcji
krytycznej przez wątek A. Po zakooczeniu realizacji sekcji
krytycznej wątku A realizacja wątku B zostanie wznowiona.
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
22
11
2009-12-15
Monitor jako narzędzie realizacji sekcji krytycznej
•
•
•
•
•
mechanizm pozwalający na blokowania dostępu do obiektu;
blokowanie odbywa się poprzez zajęcie monitora obiektu;
monitor może zastad zajęty tylko przez jeden wątek;
jeśli wątek A chce zająd monitor obiektu, który jest aktualnie w posiadaniu
wątku B, to realizacja wątku A jest wstrzymywana do momentu zwolnienia
monitora przez wątek B;
każdy obiekt występujący w programie posiada oddzielny monitor.
Wątek 1
Wątek 2
Monitor
sekcja
krytyczna
sekcja
krytyczna
Wspólny
zasób
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
23
Monitor w języku Java
synchronized (nazwaObiektu)
//zajęcie monitora obiektu
{
...
instrukcje tworzące sekcję krytyczną
...
}
//zwolnienie monitora obiektu
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
24
12
2009-12-15
Przykład
class Watek1 implements Runnable {
public void run()
{
synchronized (System.out) {
for (int i = 1; i <= 10; i++) {
try {
Thread.sleep(100);
}
catch (InterruptedException e) {
}
System.out.print("A");
}
}
}
}
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
25
.....
class Watek2 implements Runnable {
public void run()
{
synchronized (System.out) {
for (int i = 1; i <= 10; i++) {
try
{
Thread.sleep(100);
}
catch(InterruptedException e) {
}
System.out.print("B");
}
}
}
}
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
26
13
2009-12-15
.....
public class WspolneZasoby {
public static void main(String [] args) {
Thread g = new Thread(new Watek1());
Thread p = new Thread(new Watek2());
g.start();
p.start();
System.out.println("KONIEC");
}
}
Wyniki działania programu:
KONIEC
AAAAAAAAAABBBBBBBBBB
UWAGA: Program nie określa, który wątek zajmie monitor obiektu System.out jako pierwszy. Z
tego powodu przy kolejnej realizacji programu można uzyskad wynik:
KONIEC
BBBBBBBBBBAAAAAAAAAA
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
27
Metoda wait
•
•
•
synchronized (obiekt) {
...
obiekt.wait()
...
}
musi byd wywoływana z sekcji krytycznej wątku (gdy wątek zajął monitor
obiektu obiekt),
powoduje, że realizacja wątku jest zawieszana i wątek zwalnia monitor
(który może zostad zajęty przez inny wątek),
realizacja zawieszonego wątku może zostad wznowiona wówczas, gdy inny
wątek zajmie monitor obiektu obiekt i uruchomi metodę notify() lub
notifyAll().
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
28
14
2009-12-15
Metoda notify
synchronized (obiekt) {
...
obiekt.notify()
...
}
• wznawia działanie jednego (wybranego przypadkowo) wątku
wstrzymanego wcześniej za pomocą metody obiekt.wait().
Realizacja wznowionego wątku może rozpocząd się po
zakooczeniu realizacji sekcji krytycznej bieżącego wątku
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
29
Metoda notifyAll
synchronized (obiekt)
{
...
obiekt.notifyAll()
...
}
• wznawia działanie wszystkich wątków wstrzymanych
wcześniej za pomocą metody obiekt.wait(). Realizacja jednego
z nich rozpocznie się po zakooczeniu realizacji sekcji krytycznej
bieżącego wątku.
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
30
15
2009-12-15
Problem producenta i konsumenta
Producent
Konsument
Pojemnik
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
31
P-K, wersja I
class Pojemnik
{
private int liczba;
synchronized public int pobierz() {
System.out.println("Z pojemnika pobierana jest wartosc: " +
liczba);
return liczba;
}
synchronized public void wstaw(int liczba) {
System.out.println("Do pojemnika wstawiana jest wartosc: " +
liczba);
this.liczba = liczba;
}
}
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
32
16
2009-12-15
P-K, wersja I, ciąg dalszy
class Producent implements Runnable {
Pojemnik p;
Producent(Pojemnik p) {
this.p = p;
}
public void run() {
for (int i = 1; i <= 10; i++) {
try {
Thread.sleep((int) (100 * Math.random()));
}
catch (InterruptedException e) { }
p.wstaw(i);
}
}
}
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
33
P-K, wersja I, ciąg dalszy
class Konsument implements Runnable {
Pojemnik p;
Konsument(Pojemnik p) {
this.p = p;
}
public void run() {
for (int i = 1; i <= 10; i++) {
try {
Thread.sleep((int) (100 * Math.random()));
}
catch (InterruptedException e){ }
p.pobierz();
}
}
}
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
34
17
2009-12-15
P-K, wersja I, ciąg dalszy
public class ProducentKonsument1 {
public static void main(String[] args) {
Pojemnik poj = new Pojemnik();
Producent prod = new Producent(poj);
Konsument kons = new Konsument(poj);
Thread watek1 = new Thread(prod);
Thread watek2 = new Thread(kons);
watek1.start();
watek2.start();
}
}
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
35
P-K, wersja I, ciąg dalszy
Efekt działania programu:
Do pojemnika wstawiana jest wartosc: 1
Z pojemnika pobierana jest wartosc: 1
Do pojemnika wstawiana jest wartosc: 2
Do pojemnika wstawiana jest wartosc: 3
Do pojemnika wstawiana jest wartosc: 4
Z pojemnika pobierana jest wartosc: 4
Do pojemnika wstawiana jest wartosc: 5
Do pojemnika wstawiana jest wartosc: 6
Do pojemnika wstawiana jest wartosc: 7
Do pojemnika wstawiana jest wartosc: 8
Z pojemnika pobierana jest wartosc: 8
Do pojemnika wstawiana jest wartosc: 9
Do pojemnika wstawiana jest wartosc: 10
Z pojemnika pobierana jest wartosc: 10
Z pojemnika pobierana jest wartosc: 10
Z pojemnika pobierana jest wartosc: 10
Z pojemnika pobierana jest wartosc: 10
Z pojemnika pobierana jest wartosc: 10
Z pojemnika pobierana jest wartosc: 10
Z pojemnika pobierana jest wartosc: 10
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
36
18
2009-12-15
P-K, wersja II
class Pojemnik {
private int liczba;
private boolean czyJestWartoscWPojemniku = false;
public int pobierz() {
while (!czyJestWartoscWPojemniku) ; //pusta petla
System.out.println("Z pojemnika pobierana jest wartosc: " + liczba);
czyJestWartoscWPojemniku = false;
return liczba;
}
public void wstaw(int liczba) {
while (czyJestWartoscWPojemniku) ; //pusta petla
System.out.println("Do pojemnika wstawiana jest wartosc: " + liczba);
this.liczba = liczba;
czyJestWartoscWPojemniku = true;
}
}
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
37
P-K, wersja II, ciąg dalszy
Efekt działania programu:
Do pojemnika wstawiana jest wartosc: 1
Z pojemnika pobierana jest wartosc: 1
Do pojemnika wstawiana jest wartosc: 2
Z pojemnika pobierana jest wartosc: 2
Do pojemnika wstawiana jest wartosc: 3
Z pojemnika pobierana jest wartosc: 3
Do pojemnika wstawiana jest wartosc: 4
Z pojemnika pobierana jest wartosc: 4
Do pojemnika wstawiana jest wartosc: 5
Z pojemnika pobierana jest wartosc: 5
Do pojemnika wstawiana jest wartosc: 6
Z pojemnika pobierana jest wartosc: 6
Do pojemnika wstawiana jest wartosc: 7
Z pojemnika pobierana jest wartosc: 7
Do pojemnika wstawiana jest wartosc: 8
Z pojemnika pobierana jest wartosc: 8
Do pojemnika wstawiana jest wartosc: 9
Z pojemnika pobierana jest wartosc: 9
Do pojemnika wstawiana jest wartosc: 10
Z pojemnika pobierana jest wartosc: 10
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
38
19
2009-12-15
P-K, wersja III
class Pojemnik {
private int liczba;
private boolean czyJestWartoscWPojemniku = false;
synchronized public int pobierz() {
if (!czyJestWartoscWPojemniku)
try {
wait();
}
catch (InterruptedException e) { }
System.out.println("Z pojemnika pobierana jest wartosc: " +
liczba);
czyJestWartoscWPojemniku = false;
notify();
return liczba;
}
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
39
P-K, wersja III, ciąg dalszy
synchronized public void wstaw(int liczba) {
if (czyJestWartoscWPojemniku)
try {
wait();
}
catch (InterruptedException e) {
}
System.out.println("Do pojemnika wstawiana jest wartosc: „
+ liczba);
czyJestWartoscWPojemniku = true;
this.liczba = liczba;
notify();
}
}
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
40
20
2009-12-15
P-K, wersja III, ciąg dalszy
Efekt działania programu:
Do pojemnika wstawiana jest wartosc: 1
Z pojemnika pobierana jest wartosc: 1
Do pojemnika wstawiana jest wartosc: 2
Z pojemnika pobierana jest wartosc: 2
Do pojemnika wstawiana jest wartosc: 3
Z pojemnika pobierana jest wartosc: 3
Do pojemnika wstawiana jest wartosc: 4
Z pojemnika pobierana jest wartosc: 4
Do pojemnika wstawiana jest wartosc: 5
Z pojemnika pobierana jest wartosc: 5
Do pojemnika wstawiana jest wartosc: 6
Z pojemnika pobierana jest wartosc: 6
Do pojemnika wstawiana jest wartosc: 7
Z pojemnika pobierana jest wartosc: 7
Do pojemnika wstawiana jest wartosc: 8
Z pojemnika pobierana jest wartosc: 8
Do pojemnika wstawiana jest wartosc: 9
Z pojemnika pobierana jest wartosc: 9
Do pojemnika wstawiana jest wartosc: 10
Z pojemnika pobierana jest wartosc: 10
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
41
Zjawisko blokady (deadlock)
• Blokada - sytuacja w której:
– wątek A: zajął monitor obiektu I, i nie zwalniając go chce zająd
monitor obiektu II,
– wątek B: zajął monitor obiektu II, i nie zwalniając go chce zając
monitor obiektu I.
• Powstanie blokady jest bardzo trudnym do wykrycia błędem
logicznym. Języki programowania nie posiadają
mechanizmów zapobiegających powstawaniu i/lub usuwaniu
blokad - jedynym sposobem ich uniknięcia jest prawidłowe
zaprojektowanie algorytmu przetwarzania danych.
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
42
21
2009-12-15
Przykład blokady (1)
class Obiekt {
void metodaPierwsza() {
System.out.println("START - metodaPierwsza *„
+ Thread.currentThread().getName() + "]");
try {
Thread.sleep(10);
}
catch (InterruptedException e) { }
System.out.println("STOP - metodaPierwsza [" +
Thread.currentThread().getName() + "]");
}
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
43
Przykład blokady (2)
void metodaDruga()
{
System.out.println("START - metodaDruga [" +
Thread.currentThread().getName() + "]");
try {
Thread.sleep(10);
}
catch (InterruptedException e) {
}
System.out.println("STOP - metodaDruga [" +
Thread.currentThread().getName() + "]");
}
}
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
44
22
2009-12-15
Przykład blokady (3)
class Watek1 extends Thread {
Obiekt o1;
Obiekt o2;
Watek1(Obiekt o1,Obiekt o2,String nazwa)
super(nazwa);
this.o1 = o1;
this.o2 = o2;
}
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
{
45
Przykład blokady (4)
public void run() {
synchronized(o1) {
o1.metodaPierwsza();
synchronized (o2) {
o2.metodaDruga();
}
}
}
}
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
46
23
2009-12-15
Przykład blokady (5)
class Watek2 extends Thread {
Obiekt o1;
Obiekt o2;
Watek2(Obiekt o1,Obiekt o2, String nazwa)
super(nazwa);
this.o1 = o1;
this.o2 = o2;
}
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
{
47
Przykład blokady (6)
public void run() {
synchronized (o2)
{
o2.metodaPierwsza();
synchronized (o1) {
o1.metodaDruga();
}
}
}
}
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
48
24
2009-12-15
Przykład blokady (7)
public class Blokada1 {
public static void main(String [] args)
Obiekt obiekt1 = new Obiekt();
Obiekt obiekt2 = new Obiekt();
{
Thread watek1 = new Watek1(obiekt1, obiekt2,"w1");
Thread watek2 = new Watek2(obiekt1, obiekt2,"w2");
watek1.start();
watek2.start();
}
}
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
49
Przykład blokady (8)
Efekt działania programu:
START - metodaPierwsza [w1]
START - metodaPierwsza [w2]
STOP - metodaPierwsza [w1]
STOP - metodaPierwsza [w2]
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
50
25
2009-12-15
Zjawisko zagłodzenia wątku (starvation)
 Zagłodzenie - sytuacja, w której oczekujący wątek nie zostaje
dopuszczony przez inne wątki do realizacji zdefiniowanego w
nim kodu programu.
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
51
Przykład zagłodzenia wątku(1)
class Liczniki {
int pole1 = 0;
int pole2 = 0;
void zwiekszPole1() {
pole1++;
}
void zwiekszPole2() {
pole2++;
}
synchronized void wyswietlPola() {
System.out.println("Pole1 = " + pole1);
System.out.println("Pole2 = " + pole2);
}
}
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
52
26
2009-12-15
Przykład zagłodzenia wątku(2)
class Watek1 extends Thread {
Liczniki licz;
Watek1(Liczniki licz) {
this.licz = licz;
}
public void run() {
for (int i = 0; i < 1000; i++) {
synchronized(licz) {
licz.zwiekszPole1();
}
}
licz.wyswietlPola();
}
}
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
53
Przykład zagłodzenia wątku(3)
class Watek2 extends Thread {
Liczniki licz;
Watek2(Liczniki licz) {
this.licz = licz;
}
public void run() {
for (int i = 0; i < 1000; i++)
{
synchronized(licz)
{
licz.zwiekszPole2();
}
}
licz.wyswietlPola();
}
}
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
54
27
2009-12-15
Przykład zagłodzenia wątku(4)
public class Zaglodzenie1 {
public static void main(String [] args)
Liczniki licz = new Liczniki();
{
Thread watek1 = new Watek1(licz);
Thread watek2 = new Watek2(licz);
watek1.start();
watek2.start();
}
}
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
55
Przykład zagłodzenia wątku(5)
• Efekt działania programu:
Pole1 = 1000
Pole2 = 0
Pole1 = 1000
Pole2 = 1000
• W powyższym przykładzie w trakcie realizacji wątku
pierwszego czas pomiędzy zwolnieniem monitora obiektu licz,
a jego ponownym zajęciem (w kolejnym obiegu pętli) jest zbyt
krótki, aby drugi wątek zdołał zająd wspomniany monitor.
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
56
28
2009-12-15
Przeciwdziałanie zagłodzeniu (1)
• Mechanizmem nie dopuszczającym do zagłodzenia wątku jest
metoda yield zdefiniowana w klasie Thread:
• public static void yield()
• jej wywołanie powoduje chwilowe zawieszenie realizacji
bieżącego wątku i przydzielenie czasu działania procesora
następnemu wątkowi. Stosowanie tej metody gwarantuje, że
nie dojdzie do zagłodzenia wątku.
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
57
Przeciwdziałanie zagłodzeniu (2)
class Watek1 extends Thread {
Liczniki licz;
Watek1(Liczniki licz) {
this.licz = licz;
}
public void run()
{
for (int i = 0; i < 1000; i++) {
synchronized(licz) {
licz.zwiekszPole1();
}
if (i % 100 == 0)
Thread.yield();
}
licz.wyswietlPola();
}
}
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
58
29
2009-12-15
Przeciwdziałanie zagłodzeniu (3)
class Watek2 extends Thread {
Liczniki licz;
Watek2(Liczniki licz) {
this.licz = licz;
}
public void run()
{
for (int i = 0; i < 1000; i++) {
synchronized(licz) {
licz.zwiekszPole2();
}
if (i % 100 == 0)
Thread.yield();
}
licz.wyswietlPola();
}
}
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
59
Przeciwdziałanie zagłodzeniu (4)
• Efekt działania programu:
Pole1 = 1000
Pole2 = 901
Pole1 = 1000
Pole2 = 1000
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
60
30
2009-12-15
Semafor w programowaniu
Semafor – narzędzie synchronizacji, sterujący dostępem do wspólnego zasobu,
posiada licznik określający możliwą do wykorzystania liczbę jednostek deficytowego
zasobu.
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
61
Operacje wykonywane na semaforze – operacja P
• P – prolaag (holenderski) = probeer te verlagen oznacza
próbuj i zmniejsz
• Operacja wykonywana w chwili, gdy wątek chce zająd pewną
liczbę jednostek zasobu
• Jeśli licznik semafora (liczba wolnych jednostek zasobu) jest
większy lub równy od liczby potrzebnych jednostek, to
następuje zmniejszenie licznika o liczbę wymaganych przez
wątek jednostek.
• Jeśli wartośd licznika jest mniejsza od liczby potrzebnych
jednostek, to wątek zostaje wstrzymany aż do momentu, gdy
wartośd licznika odpowiednio wzrośnie.
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
62
31
2009-12-15
Operacje wykonywane na semaforze – operacja V
• V – verhoog (holenderski) oznacza zwiększ
• Operacja wykonywana w chwili, gdy wątek chce zwolnid
pewną liczbę jednostek zasobu
• Następuje zwiększenie wartości licznika o liczbę zwalnianych
jednostek zasobu.
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
63
Implementacja (Silberschatz, Galvin, and Gagne, 1999)
public class Semaphore {
public Semaphore() {
value = 0;
}
public Semaphore(int v) {
value = v;
}
public synchronized void P() { /* see next slide */ }
public synchronized void V() { /* see next slide */ }
private int value;
}
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
64
32
2009-12-15
Implementacja (Silberschatz, Galvin, and Gagne, 1999)
public synchronized void P() {
while (value <= 0) {
try {
wait();
}
catch (InterruptedException e) { }
}
value --;
}
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
65
Implementacja (Silberschatz, Galvin, and Gagne, 1999)
public synchronized void V() {
++value;
notify();
}
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
66
33
2009-12-15
Klasyfikacja semaforów
• semafor zliczający – licznik przyjmuje wartości całkowite
• semafor binarny:
– licznik przyjmuje tylko jedną z dwóch wartości: 0 (zasób zajęty) lub 1
(zasób wolny)
– licznik może byd tylko zmieniany o 1,
– operacja V (zwiększanie licznika semafora) wykonana na semaforze o
liczniku równym 1 nie powoduje żadnych zmian.
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
67
34