Zadanie Laboratoryjne
Zaprojektować i zaimplementować program realizujący następujący problem programowania
współbieżnego:
N procesów uczestniczy w realizacji zadania „Biesiada". Działanie każdego z procesów
polega na wykonywaniu nieskończonej pętli obejmującej:
wykonywanie przez pewien czas sekcji lokalnej;
zgłoszenie zapotrzebowania na obiekt „B" lub/i obiekt „Z";
- po uzyskaniu dostępu do żądanego zasobu - przejście do sekcji krytycznej, w której
otrzymany obiekt używany jest WYŁĄCZNIE przez ten jeden proces;
- zwrócenie pobranego obiektu (obiektów) do puli i opuszczenie sekcji krytycznej.
Widocznym efektem działania każdego z procesów będzie wyświetlanie na ekranie (i
zapisywanie do pliku) komunikatów generowanych tuż po wejściu i tuż przed opuszczeniem
sekcji krytycznej, o postaci:
,,[mm:ss:cc] proces nr [X]; pobieram [B i/lub F]." ,,[mm:ss:cc] proces nr [X]; zwracam [B i/lub F]." gdzie [mm:ss:cc] oznacza czas w formacie minuty:sekundy::setne [X] jest numerem procesu.
1. Realizacja synchronizacji/wzajemnego wykluczania:
Przy pomocy wspólnej pamięci (zmienne globalne). Można wykorzystać dowolny
algorytm wzajemnego wykluczania dla N procesów z wyjątkiem piekarnianego
przedstawionego w książce Ben-Ari: „podstawy projektowania współbieżnego i
rozproszonego"
Poprzez wykorzystanie semaforów (operacji Signal i Wait);
Procesy przesyłają między sobą komunikaty (proces prosi pozostałych uczestników o
zgodę; pobiera zasób po uzyskaniu od wszystkich pozytywnej odpowiedzi):
Nad realizacją zadania czuwa „zarządca" (monitor), z którym komunikują się
poszczególne procesy i który stosownie przydziela im zasoby.
2. Liczba procesów i zasobów:
3 procesy; po jednym zasobie „B" i „Z";
5 procesów; po dwa zasoby „B" i „Z".
3. Warunki dodatkowe:
Istnieje proces (nr 1) o większym priorytecie. Przy zgłoszeniu przez ten proces
zapotrzebowania, zasób jest mu przydzielany przed innymi; proces używający w tym
czasie tego zasobu natychmiast go zwraca (do lc, d; 2a).
Zasoby „B" i „Z" zawierają liczniki (o pewnym dodatnim stanie początkowym). Każde
użycie zasobu pomniejsza jego licznik. Biesiada kończy się przy wyzerowaniu (obu) „B ".
Każdy wyświetlany komunikat będzie tu rozszerzony o stan licznika pobieranego zasobu
(do 2b). Uwaga: proces nie powinien pobrać zasobu pustego, jeśli drugi nie jest jeszcze
wyczerpany.
Procesy o numerach parzystych potrzebują do realizacji sekcji krytycznej dostępu
jednocześnie do „B" i „Z". Do sekcji krytycznej wejdą dopiero po otrzymaniu obu. Po
zakończeniu sekcji krytycznej zwracają je jednocześnie (do 1 a, b ,d).
Plik Display.ads:
--Pakiet display: chronione wyświetlanie na ekranie
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
package Display is
subtype MyString is Stringd. .100) ;
protected type ScreenType is
procedurę Write(txt: in Unbounded_String); end ScreenType;
Screen: ScreenType; end Display;
Plik Member.ads:
--Pakiet Member: definicja członka biesiady package Member is
No_of_Members: constant integer := 3;
type MemberType;
type MemberPtrType is access MemberType;
type MemberArray is array(1..No_of_Members) of MemberPtrType;
task type MemberType is
entry Init(The_Num: in integer; AllMem:
in MemberArray); end MemberType;
end Member;
Plik Display.adb:
Plik Member.adb:
—Pakiet display: chronione wyświetlanie na ekranie —Pakiet Member: definicja biesiadnika
with Ada.Text_IO;
with Ada.Integer_Text_IO;
with Ada.Calendar; use Ada.Calendar;
package body Display is
protected body ScreenType is
procedurę Write(txt: in Unbounded_String) is
Now: Time;
Sec, MM, SS, CC: Float; begin
Now := Clock;
Sec := Float(Seconds(Now));
MM := Float'Floor(Sec/3600.0) ; Sec := Sec - MM*3600.00; MM := FloafFloor (Sec/60.0) ; Sec := Sec - MM*60.00; SS := Float'Floor(Sec); Sec := Sec - SS; CC := Float'Floor(Sec*100.0); Ada.Integer_Text_IO.Put(item => Integer(MM),
width => 2) ; Ada.Text_IO.Put (':'); Ada.Integer_Text_IO.Put(item => Integer(SS),
width => 2); Ada.Text_IO.Put(':'); Ada.Integer_Text_IO.Put(item => Integer(CC),
width => 2); Ada.Text_IO.Put(* 'J.Ada . Text_IO. Put_Line (To_String (txt)) ; end Write;
end ScreenType; end Display;
with Display; use Display; with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; with Ada.Numerics.Float_Random; use Ada.Numerics.Float_Random;
package body Member is
task body MemberType is My_Number: integer; All_Members: MemberArray;
numer biesiadnika
tablica wskaźników
do biesiadników
G: Generator; -- generator liczb
-- pseudolosowych txt: Unbounded_String; pom: Float; begin —czesc inicjująca
accept Init(The_Num: in integer; AllMem:
in MemberArray) do My_Number := The_Num; All_Members := AllMem; end Init;
delay(duration(My_Number)/10.0); Reset(G);
—czesc zasadnicza: nieskończona pętla loop
pom := Random(G) ; delay Duration(pom);
txt := To_Unbounded_String("proces nr") & integer'image(My_Number) & "; "; Screen.Write(txt); exit when pom < 0.1;
end loop; end MemberType;
end Member;
Plik Biesiada.adb:
with Member; use Member;
procedurę Biesiada is
Biesiadnicy: MemberArray; begin
for i in 1..No_of_members loop
Biesiadnicy(i) := new MemberType;
end loop;
for i in 1..No_of_members loop
Biesiadnicy(i).Init(i, Biesiadnicy) ,
end loop; end;