Abb. 2: Klassendiagramm Teil B
protected Linda_Env is entry Output (T: in Tuple_Type); entry Input (T: in out Tuple_Type); entry Read (T: in out Tuple_Type); private Tuplespace, Waiting: Tuplespace_Type; end Linda_Env;
Task 1 | Task 2 |
OUTPUT ('MULT',2,3); | OUTPUT('MULT',4,5); |
INPUT ('PROD', NATURAL); | INPUT('PROD',NATURAL); |
OUTPUT ('MULT',6,7); |
Tupelraum "Tupelspace"
‘MULT’ |
2 |
3 |
|
‘MULT’ |
4 |
5 |
|
Tupelraum "Waiting"
T1.BLOCKER.wait |
‘PROD’ |
NATURAL |
||
T2.BLOCKER.wait |
‘PROD’ |
NATURAL |
||
(Task 1 und Task 2 sind nun blockiert)
protected body Linda_Env is entry Output (T: in Tuple_Type) when true is I: Tuplespace_Iterator_Type; NT, RT: Tuple_Type := T; B: Blocker_Access; OR: boolean; -- Nur lese Task (LINDA READ Primitive) begin -- Zum Vergleich einen formalen Blocker einfuegen Insert_First (NT, Blocker_Parameter_Type'(true, null, false)); -- Solange, bis ein auf Input wartender Task gefunden wurde loop -- einen wartenden Task finden I := Find_Matching (Waiting, NT); -- Das Tupel mit dem des wartenden Tasks binden RT := Bind (Value (I), NT); -- Den wartenden Task aus Warteraum entfernen Delete (I); OR := Blocker_Parameter_Type(Value(First(RT))).Only_Reading; -- Den Blocker entnehmen B := Blocker_Parameter_Type (Value (First (RT))).B; Delete_First (RT); -- Den wartenden Task erloesen B.all.Release (RT); exit when not OR; end loop; exception -- Wenn kein wartender Task gefunden wurde when No_Tuple_Matches -- dann das Tupel in den Tupelraum eintragen => Insert_First (TupleSpace, T); end Output; entry Input (T: in out Tuple_Type) when true is I: Tuplespace_Iterator_Type; B: Blocker_Access; NT: Tuple_Type := T; begin -- Ein passendes Tupel im Tupelraum suchen I := Find_Matching (TupleSpace, T); -- Die Tupel binden T := Bind (Value (I), T); -- Das gefundene Tupel aus dem Tupelraum entfernen Delete (I); exception -- wenn kein passendes Tupel im Tupelraum gefunden wurde when No_Tuple_Matches -- einen Blocker erzeugen um den aufrufenden Task warten -- zu lassen B := new Blocker_Type; -- Den Blocker in das Tupel eintragen Insert_First (NT, Blocker_Parameter_Type'(false, B,false)); -- Das Tupel in den Warteraum stellen Insert_First (Waiting, NT); -- Und den Task endlich warten lassen requeue B.all.Wait; end Input;Bermerkung: Der Programmcode für Read ist fast analog
Werden verwendet um den INPUT Task solange aufzuhalten, bis ein für die Input Funktion passendes Tupel mit OUTPUT in den Tupelraum gestellt wird.
Solche Blocker werden einem Tupel im Waiting-Tupelraum mitgegeben, um es einem Prozeß, der mit OUTPUT ein passendes Tupel ausgibt, zu ermöglichen den wartenden Prozeß aufzuwecken (siehe Prozedur output)
with Tuple; use Tuple; package Blocker is protected type Blocker_Type is entry Wait (T: in out Tuple_Type); procedure Release (T: in Tuple_Type); private Tup: Tuple_Type; Blocked: boolean := true; end Blocker_Type; end Blocker; package body Blocker is protected body Blocker_Type is entry Wait (T: in out Tuple_Type) when not Blocked is begin T := Tup; end Wait; procedure Release (T: in Tuple_Type) is begin Tup := T; Blocked := false; end; end Blocker_Type; end Blocker;