program ferryboat; {a ferryboat crosses a river. Master - slave synchronization Lin Jensen November 17, 1996} {------- The basic time unit is 1 minute --------} USES Clock, mcobj, simobj, statobj, queue, coproc, Proc_man, message; CONST CarCapacity = 50; {number of cars that ferryboat can carry} StartTime = 60*6; StopTime = StartTime + 60*12 + 6; {12 hours & unloading time} TYPE city = (Quebec, Levis); {two sides of the river} {the active processes } FerryPtr = ^Ferry; Ferry = object(procdescr) CarsOn : FifoQueue; starttime: real; {when this ferry starts its daily schedule} constructor Init(boatnum:integer; starttimeP: real); procedure lifecycle; virtual; procedure Board (Quebec:city); {board cars procedure at either side} procedure Unload; {cars leave one by one} end; CarPtr = ^Car; Car = object (Procdescr) Origin : City; Size : 1..10; ArrivalTime : real; constructor Init (side : city; num:integer); procedure lifecycle; virtual; end; VAR Arrivals : array [city] of RandomNegExp; {arrival distribution} Dock : array [city] of portdescr; {cars at the docks} Sink : array [city] of Counter; FlowTime : Histogram; {travel time (both directions)} const CityName : array [city] of string[6] = ('Quebec','Levis '); constructor Car.Init (side : city; num:integer); begin procdescr.init ('Car',num); Origin := side; Size := 1; {all cars are for now the same size. We might add trucks} end; procedure Car.lifecycle; var ford : CarPtr; {Next arrival} IamHere:notePtr; begin Sleep_for (Arrivals[origin].NegExp); ArrivalTime := TheClock.telltime; {--- schedule next arrival ---} NEW (ford, init (Origin, getnumber+1)); RESUME (ford); {wait by sending message to DOCK message port} New (IamHere, Init); Dock[origin].send (IamHere); SUSPEND; {assume we have now been delivered to the other side} DISPOSE (IamHere, Destroy); {note no longer needed} FlowTime.Update (Time - ArrivalTime); Sink[origin].Update; end; constructor Ferry.Init (boatnum:integer;starttimeP: real); begin procdescr.init('FERRY',boatnum); CarsOn.Init; starttime := StartTimeP; end; procedure Ferry.lifecycle; begin {start out at Quebec, wait 15 or 45 minutes for cars to start arriving} Sleep_Until (StartTime); WHILE TRUE DO {go back and forth across river} BEGIN {take on board up to car capacity} Board (Quebec); Sleep_for (20); {Cross the river} Unload; {should be ready to depart in 10 minutes} Board (Levis); Sleep_for (20); {Cross the river} Unload; {should be ready to depart in 10 minutes} END; end; {ferry lifecycle} procedure Ferry.Board (Quebec:city); {take on board up to car capacity} begin while (CarsOn.CARD < CarCapacity) AND NOT Dock[Quebec].messages.IsEmpty do CarsOn.Tail_Insert (Dock[quebec].receive); Write ('Ferry ',getnumber,' sails from ',cityname[Quebec],' with ',carson.card,' cars at'); TheClock.rite; If Not dock[Quebec].messages.IsEmpty then write (' ... leaving behind ', dock[quebec].messages.card); writeln; end; {board} procedure Ferry.Unload; var NextDeparture : Real; begin NextDeparture := TIME + 10; {let the cars off} While not carson.isempty do begin Resume (notePtr(carson.get)^.sender); Sleep_For (0.1); {it takes them some time to drive off} end; Sleep_Until (NextDeparture); end; {unload} procedure Initialize; var boat : ferryptr; auto : carptr; begin TheClock.AdvanceTo (StartTime - 15); {cars start arriving 15 min before first boat at 6 a.m.} Writeln ('Ferry boat crosses the river at Quebec. ', 'Time units are minutes.'); writeln (' ----- 2 boats ----'); write (' Simulation starts at'); Theclock.rite; writeln; Arrivals[quebec].init (12393, 0.7); Arrivals[levis].init (83521, 0.7); Dock [quebec].init; Dock [Levis].init; Dock [quebec].specificlabel ('Quebec dock'); Dock [Levis].specificlabel ('Levis dock'); sink [quebec].init; {count departures, note destination is opposite from source} sink [quebec].specificlabel ('Cars reaching Levis'); sink [levis].init; sink [levis].specificlabel ('Cars reaching Quebec'); Flowtime.init (20,90,14); {---- the processes ---------} NEW (boat, Init(1, StartTime) ); {first sailing at 6 a.m.} resume (boat); {Second boat:-----} NEW (boat, Init(2, StartTime + 30)); resume (boat); New (auto, Init(quebec, 0)); {first cars of the morning} resume (auto); New (auto, Init(levis, 0)); resume (auto); end; begin {------main-----} Initialize; Monitor.Runsimulation (StopTime, 22); reporter.reportall; end.