Implementacja bariery w RMI i adzie

Transkrypt

Implementacja bariery w RMI i adzie
Implementacja mechanizmu bariery w środowisku RMI oraz
w j˛ezyku Ada (z wykorzystaniem pakietu Glade)
Jakub Gorgolewski,
nr indeksu 55456
15 czerwca 2005
1
Wst˛ep
Celem ćwiczenia było zaimplementowanie mechanizmu bariery. Przyj˛eto nast˛epujace
˛ założenia odnośnie
jej funkcjonalności. Każdy dost˛ep do bariery realizowany jest z jednym parametrem o nazwie count.
Proces pozostaje zablokowany na barierze dopóki parametr count jest mniejszy niż liczba procesów
zablokowanych na barierze. Warunkiem wyjścia z blokady nazywany jest w tej pracy warunek:
liczba procesów na barierze ≥ parametr count
Przy realizacji barier przyj˛eto, że parametr count może przyjmować różne wartości dla różnych procesów, co może prowadzić do takich sytuacji, że proces wywołujacy
˛ barier˛e powoduje spełnienie warunku
wyjścia dla innych procesów na niej zablokowanych nie majac
˛ samemu spełnionego tego warunku.
2
Implementacja w środowisku RMI
Interfejs serwera bariery jest prosty. Składa si˛e z deklaracji jednej jedno argumentowej funkcji realizujacej
˛ główne zadanie bariery. Kod interfejsu przedstawiony jest na listingu 5. Kod klienta jest również
prosty, gdyż sprowadza si˛e do połaczenia
˛
z serwerem RMI i wywołania metody barrier z argumentem
pobranym z linii komend. Został on przedstawiony na listingu 6.
Najważniejsze przetwarzanie realizowane jest po stronie serwera w metodzie barrier w linijkach
23–37. Wykorzystywane w nim sa˛ nast˛epujace
˛ prywatne pola typu int:
• CurrentProcNum – przechowujace
˛ liczb˛e procesów aktualnie b˛edacych
˛
na blokadzie
• NotifyProcNum – przechowujace
˛ liczb˛e procesów b˛edacych
˛
na blokadzie w momencie, gdy rozpocz˛eto testowanie warunku wyjścia
• NotifyReceived – przechowujace
˛ liczb˛e procesów, które jeszcze nie sprawdziły warunku wyjścia w tym cyklu
Należy zwrócić uwag˛e, że jest to metoda synchronizowana, co oznacza, że równocześnie do tej metody
może si˛e odwoływać tylko jeden proces. Przetwarzanie realizowane w kodzie przedstawionym na listingu
1 można podzielić na kilka etapów:
1
23–25 kod ten ma zapobiegać sytuacji, gdy bariera wywoływana jest przez nowy proces zanim sprawdzone
zostana˛ warunki wyjścia wszystkich procesów oczekujacych
˛
na barierze;
26–31 przygotowanie zmiennych i obudzenie procesów oczekujacych
˛
na barierze;
32–35 odnotowanie sprawdzenia warunku wyjścia i samo jego sprawdzenie – jeśli jest prawdziwy przerywana jest p˛etla while, w przeciwnym wypadku proces jest usypiany
36–37 odnotowanie opuszczenia bariery
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
Listing 1: Główny kod serwera bariery - Java
while(NotifyReceived != 0) {
wait();
}
NotifyReceived = CurrentProcNum;
CurrentProcNum++;
NotifyProcNum = CurrentProcNum;
notifyAll();
while(count != NotifyProcNum) {
wait();
NotifyReceived--;
}
CurrentProcNum--;
Pełen kod serwera znajduje si˛e w listingu 7 na końcu tego dokumentu.
3
Implementacja w j˛ezyku Ada
Przy implementacji bariery w j˛ezyku Ada zastosowano nast˛epujac
˛ a˛ konfiguracj˛e (listing 12). Jedyny interfejs zdalnego wywołania (RCI– Remote Call Interface) wchodzi w skład partycji serwera i jest zadeklarowany w plikach barrierserver.ads i barrierserver.adb (listingi 10 i 11). Jako główna procedura systemu została zadeklarowana procedura BarrierManager, a jako główna procedura partycji klienckiej
BarrierClient. Dodatkowo zadeklarowano, iż partycja kliencka może kończyć prace nie czekajac
˛ na
zakończenie pracy partycji serwerowej.
Implementacja procedury BarrierClient (listing 8) jest zbliżona do jej odpowiednika w Javie, a
procedura BarrierManager (listing 9) sprowadza si˛e jedynie do oczekiwania na sygnał do zakończenia
pracy serwera.
Podobnie jak w przypadku implementacji w j˛ezyku Java, najważniejsze przetwarzanie realizowane jest
po stronie serwera. W tym przypadku rol˛e metody synchronizowanej pełni obiekt chroniony, zdefiniowany
w liniach 20–56. Wykorzystuje on cztery zmienne typu integer, gdzie trzy pełnia˛ analogiczne role co
pola opisane przy implementacji bariery w środowisku RMI. Dodatkowa zmienna, ReNotRec, służy do
zliczania ile procesów jeszcze nie zostało przekierowanych na prywatna metod˛e wejściowa˛ wait. Ponadto
w obiekcie chronionym barrier zadeklarowano 3 procedury wejścia: jedna˛ publiczna˛ – barrier i
dwie prywatne – wait i rewait. Ich kod został przedstawiony kolejno na listingach 2, 3 i 4.
W procedurze block warunki wejścia sa˛ prawdziwe wtedy i tylko wtedy, gdy wszystkie procesy
korzystajace
˛ w danej chwili z bariery opuszczaja˛ ja˛ lub zostały już przekierowane do procedury wait. Po
wejściu do procedury ustawiane sa˛ zmienne powodujace
˛ „zablokowanie” wejścia do procedury block
i „odblokowanie” wejścia do procedury wait. Dzi˛eki obecności mechanizmu warunków wejścia nie
musimy wywoływać specjalnej procedury do budzenia procesów oczekujacych,
˛
jak to było w przypadku
Javy. Dalej sprawdzane sa˛ warunki wyjścia i w przypadku ich niespełnienia sterowanie przekierowane jest
do procedury rewait.
2
Listing 2: Procedura wejścia block
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
entry block(count: in Integer)
when (NotRec = 0) and (ReNotRec = 0) is
begin
NotRec := CurProcNum;
ReNotRec := CurProcNum;
CurProcNum := CurProcNum + 1;
NotProcNum := CurProcNum;
if(count <= NotProcNum) then
CurProcNum := CurProcNum - 1;
else
ReNotRec := ReNotRec + 1;
requeue rewait;
end if;
end;
Procedura wait jest odpowiednikiem funkcji wait z j˛ezyka Java. Procesy usypiane sa˛ po przez
zablokowanie ich na warunkach wejściowych, a dokłaniej, gdy zmienna NotRec jest równa 0. Ponieważ
każdy proces, który wejdzie do procedury wait dekrementuje ta˛ zmienna˛ to ustawienie jej na n powoduje
wpuszczenie n procesów. Dalej, podobnie jak w przypadku procedury block sprawdzane sa˛ warunki
wyjścia i w przypadku ich niespełnienia sterowanie przekierowywane jest do procedury rewait.
Listing 3: Procedura wejścia wait
38
39
40
41
42
43
44
45
46
47
48
entry wait(count: in Integer)
when NotRec > 0 is
begin
NotRec := NotRec - 1;
if count <= NotProcNum then
CurProcNum := CurProcNum - 1;
ReNotRec := ReNotRec - 1;
else
requeue rewait;
end if;
end;
Procedura rewait została dodana, ponieważ nie przyj˛eto żadnych założeń co do kolejności obsługi
procesów oczekujacych
˛
na warunku wejściowym do procedury wejściowej. Procesy wywołujace
˛ rewait
sa˛ blokowane na warunku wejściowym póki kolejka procesów oczekujacych
˛
na wejście do procedury
wait nie bedzie pusta. Dzieki temu mamy gwarancj˛e, iż każdy proces oczekujacy
˛ wykona procedur˛e
wait (a co za tym idzie sprawdzenia warunków wyjścia) dokładnie raz na jeden cykl „budzenia” zainicjowany przez nowy proces wywołujacy
˛ procedure block.
Listing 4: Procedura wejścia rewait
50
51
52
53
54
55
4
entry rewait(count: in Integer)
when (NotRec = 0) and (ReNotRec > 0) is
begin
ReNotRec := ReNotRec - 1;
requeue wait;
end;
Podsumowanie
Zademonstorowane powyżej przykłady implementacji mechanizmu bariery w dwóch wysoko poziomowych j˛ezykach programowania aż prosza˛ si˛e o porównanie. Jak widać Ada w wi˛ekszym stopniu pozwala
3
si˛e skupić na samej cz˛eści implementacyjnej izolujac
˛ konfiguracj˛e środowiska pracy. Z drugiej strony, Java
dysponuje, nie tak wszechstronnymi, ale bardziej intuicyjnymi mechanizmami synchronizacji procesów.
Spis pełnych listingów plików
5
6
7
8
9
10
11
12
Interfejs bariery - Java (BarrierInterface.java), . . .
Kod klienta bariery - Java (BarrierClient.java) . . .
Kod serwera bariery - Java (BarrierServer.java) . .
Kod klienta bariery - Ada (barrierclient.adb) . . . .
Kod “zarzadcy”
˛
bariery - Ada (barriermanager.adb)
Nagłówek serwera bariery - Ada (barrierserver.ads)
Kod serwera bariery - Ada (barrierserver.adb) . . .
Konfiguracja partycji - Glade (barrierconf.cfg) . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
4
4
4
5
6
6
6
7
Listing 5: Interfejs bariery - Java (BarrierInterface.java),
.
.
.
.
.
.
.
.
1
2
3
4
5
6
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface BarrierInterface extends Remote{
public void barrier(int count) throws RemoteException;
}
Listing 6: Kod klienta bariery - Java (BarrierClient.java)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import
import
import
import
java.rmi.Naming;
java.rmi.RMISecurityManager;
java.rmi.RemoteException;
java.rmi.server.UnicastRemoteObject;
public class BarrierClient {
public static void main(String[] args) {
if(System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}
try {
String name = "//localhost:1099/Barrier";
BarrierInterface barrier = (BarrierInterface) Naming.lookup(
name);
System.out.println(args[0]);
barrier.barrier(Integer.parseInt(args[0]));
} catch(Exception e) {
System.err.println("Barrier critical: " + e.getMessage());
e.printStackTrace();
}
}
}
Listing 7: Kod serwera bariery - Java (BarrierServer.java)
1
2
3
4
5
import
import
import
import
import
java.rmi.Naming;
java.rmi.RMISecurityManager;
java.rmi.RemoteException;
java.rmi.server.UnicastRemoteObject;
java.lang.Thread;
4
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
public class BarrierServer
extends UnicastRemoteObject
implements BarrierInterface {
private int CurrentProcNum;
private int NotifyProcNum;
private int NotifyReceived;
public BarrierServer() throws RemoteException {
super();
CurrentProcNum = 0;
NotifyReceived = 0;
}
synchronized public void barrier(int count) {
try {
while(NotifyReceived != 0) {
wait();
}
NotifyReceived = CurrentProcNum;
CurrentProcNum++;
NotifyProcNum = CurrentProcNum;
notifyAll();
while(count != NotifyProcNum) {
wait();
NotifyReceived--;
}
CurrentProcNum--;
} catch (Exception e) {
System.err.println("BarrierServer critical while invocation: "
+ e.getMessage());
e.printStackTrace();
}
}
public static void main(String[] args) {
if(System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}
String name = "//localhost:1099/Barrier";
try {
BarrierServer engine = new BarrierServer();
Naming.bind(name, engine);
System.out.println("BarrierServer online");
} catch(Exception e) {
System.err.println("BarrierServer critical: " + e.getMessage()
);
e.printStackTrace();
}
}
}
Listing 8: Kod klienta bariery - Ada (barrierclient.adb)
5
1
2
3
4
5
6
7
8
9
10
11
12
13
procedure barrierClient is
package IntIO is new ada.text_io.integer_io(integer);
use IntIO;
begin
if argument_count = 0 then
put("One argument required!");
else
barrierServer.barrier(integer’value(argument(1)));
end if;
end;
Listing 9: Kod “zarzadcy”
˛
bariery - Ada (barriermanager.adb)
1
2
3
4
5
6
7
8
9
10
with ada.text_io, barrierServer;
use ada.text_io;
procedure barrierManager is
Request : String (1 .. 16);
Length
: Natural;
begin
put("Insert anything to quit.");
get_line(Request, Length);
end barrierManager;
Listing 10: Nagłówek serwera bariery - Ada (barrierserver.ads)
with ada.text_io, ada.command_line, barrierServer;
use ada.text_io, ada.command_line;
1
2
3
4
5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package barrierServer is
pragma Remote_Call_Interface;
procedure barrier(arg: in integer);
end barrierServer;
Listing 11: Kod serwera bariery - Ada (barrierserver.adb)
with ada.text_io;
use ada.text_io;
package body barrierServer is
protected type barrier_type is
entry block(count: in Integer);
private
entry wait(count: in Integer);
entry rewait(count: in Integer);
CurProcNum: Integer
NotProcNum: Integer
NotRec:
Integer
ReNotRec:
Integer
end barrier_type;
:=0;
:=0;
:=0;
:=0;
protected body barrier_type is
6
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
1
2
3
4
5
6
7
8
9
10
11
entry block(count: in Integer)
when (NotRec = 0) and (ReNotRec = 0) is
begin
NotRec := CurProcNum;
ReNotRec := CurProcNum;
CurProcNum := CurProcNum + 1;
NotProcNum := CurProcNum;
if(count <= NotProcNum) then
CurProcNum := CurProcNum - 1;
else
ReNotRec := ReNotRec + 1;
requeue rewait;
end if;
end;
entry wait(count: in Integer)
when NotRec > 0 is
begin
NotRec := NotRec - 1;
if count <= NotProcNum then
CurProcNum := CurProcNum - 1;
ReNotRec := ReNotRec - 1;
else
requeue rewait;
end if;
end;
entry rewait(count: in Integer)
when (NotRec = 0) and (ReNotRec > 0) is
begin
ReNotRec := ReNotRec - 1;
requeue wait;
end;
end barrier_type;
barrier_inst: barrier_type;
procedure barrier(arg: in integer) is
begin
barrier_inst.block(arg);
end barrier;
end barrierServer;
Listing 12: Konfiguracja partycji - Glade (barrierconf.cfg)
configuration barrierConf is
pragma Starter(none);
pragma Boot_Location("tcp", "localhost:6000");
Server : Partition := (barrierServer);
Client : Partition ;
for Client’Termination use Local_Termination;
procedure barrierManager is in Server;
procedure barrierClient;
7
12
13
14
for Client’Main use barrierClient;
end barrierConf;
8

Podobne dokumenty