The design approach taken below began with identifying the active and passive elements in the simulation. The active elements include the barber and the customers. The barbershop is a passive element. It contains chairs in a waiting room, a single barber chair, a count of waiting customers, and a state of Open or Closed.
The Ada language provides tasks as active elements of concurrency and protected objects as passive elements of concurrency. Operations on a passive object are always called by one or more tasks, and execute within the execution schedule of the task making the call.
The actions of the barber are to sleep when there are no customers, serve a customer in one of the chairs, and close the shop when directed.
The actions of the customers are to take an available seat or leave if no seat is available. Customers also leave if the barbershop is closed.
This solution provides a task for the barber, a task for all the customers, and a protected object named Barber_Shop.
package Barber_Shop is task Barber is entry Close_Shop; end Barber; task Customers; end Barber_Shop;
with Ada.Text_IO; use Ada.Text_IO; with Ada.Numerics.Float_Random; use Ada.Numerics.Float_Random; package body Barber_Shop is Seed : Generator; type Num_Seats is range 0 .. 3; protected Shop is function Is_Open return Boolean; function Shop_Empty return Boolean; entry Take_Seat; entry Serve_Customer; procedure Close_Shop; private Shop_Open : Boolean := True; Occupied_Seats : Num_Seats := 0; end Shop; protected body Shop is function Is_Open return Boolean is begin return Shop_Open; end Is_Open; function Shop_Empty return Boolean is begin return Occupied_Seats = 0; end Shop_Empty; entry Take_Seat when Shop_Open and then Occupied_Seats < Num_Seats'Last is begin Occupied_Seats := Occupied_Seats + 1; end Take_Seat; entry Serve_Customer when Occupied_Seats > 0 is begin Occupied_Seats := Occupied_Seats - 1; end Serve_Customer; procedure Close_Shop is begin Shop_Open := False; end Close_Shop; end Shop; ------------ -- Barber -- ------------ task body Barber is procedure Cut_Hair is begin Put_Line ("Luigi is serving a customer."); delay Duration (Random (Seed) * 3.0); end Cut_Hair; begin loop select accept Close_Shop; Put_Line ("Luigi is closing the shop"); Shop.Close_Shop; else if Shop.Is_Open then if Shop.Shop_Empty then Put_Line ("Luigi is sleeping."); end if; Shop.Serve_Customer; Cut_Hair; else while not Shop.Shop_Empty loop Shop.Serve_Customer; Cut_Hair; end loop; exit; end if; end select; end loop; end Barber; --------------- -- Customers -- --------------- task body Customers is begin loop delay Duration (Random (Seed) * 6.0); select Shop.Take_Seat; Put_Line ("A customer took a seat"); else if Shop.Is_Open then Put_Line ("A customer left because all the seats were taken."); else Put_Line ("A customer left because the shop is closed."); exit; end if; end select; end loop; end Customers; begin Reset (Seed); end Barber_Shop;
with Barber_Shop; use Barber_Shop; procedure Main is begin delay 60.0; Barber.Close_Shop; end Main;
I think the requirement "If all waiting room chairs are full when a new customer arrives that arriving customer will leave the barbershop" is not satisfied. In fact, the customer will wait when "Occupied_Seats < Num_Seats'Last" equals to False. To comply with this requirement, asynchronous select statement should be used instead.
ReplyDeleteThere are two conditions causing the customer to leave. One is when the shop is open and all chairs are filled. The other is when the shop is closed.
Deleteselect
Shop.Take_Seat;
Put_Line ("A customer took a seat");
else
if Shop.Is_Open then
Put_Line ("A customer left because all the seats were taken.");
else
Put_Line ("A customer left because the shop is closed.");
exit;
end if;
end select;
The selective call to shop.Take_Seat ensures that the "else" clause of the select statement will be executed immediately. If the shop is still open then the message "A customer left because all seats were taken." is output. Otherwise, the message "A customer left because the shop was closed." is output. Proof that this works is seen in execution of the program. 1) The messages are produced. 2) The program terminates correctly.
You are absolutely right. I misunderstood the behavior of conditional entry call.
DeleteGood one, I really love reading these kinds of blogs. Keep updating and write something on barber shop in Rochester and other things also.
ReplyDelete