-- In this program, we first define a simple data structure representing -- a bank account. Each account has a balance. Then we define a task type -- called "banker" which manages an account. Each banker task provides -- services such as withdraw, deposit, and balance inquiry. Each banker -- manages a specific account, but one account can have multiple bankers. -- For example, you may be withdrawing from an ATM machine while your -- employer could be making a paycheck deposit to the same bank account. -- This is obviously a critical section problem as the two "banker" tasks -- would be trying to change your balance at the same time. This first -- program sets up the basic data structures tasks, and is followed by -- a second, more sophisticated program. with Text_Io, Ada.Integer_Text_Io; use Text_Io, Ada.Integer_Text_Io; with Ada.Float_Text_Io; use Ada.Float_Text_Io; with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; procedure Concbank is -- Define account datatype: type Account is record Balance : Integer; Interest : Float; end record; type Accountptr is access Account; -- pointer to account function Makeaccount(B : Integer) return Accountptr is A : Accountptr; begin A := new Account; A.Balance := B; A.interest := 0.02; -- 2% interest return A; -- return pointer end Makeaccount; -- banker task provides the banking service: task type Banker is entry Setaccount(X : Accountptr); -- determines account to manage entry Withdraw(X : Integer); entry Deposit(X : Integer); entry Inquiry(X : out Integer); entry Quit; -- stop services end Banker; task body Banker is A : Accountptr; -- pointer to account to be managed. Stop : Boolean := False; begin accept Setaccount(X : Accountptr) do A := X; end Setaccount; while not(Stop) loop -- infinite loop select accept Inquiry(X : out Integer) do X := A.Balance; end Inquiry; or accept Deposit(X : Integer) do A.Balance := A.Balance + X; end Deposit; Put("just processed deposit"); -- not part of rendevous point New_Line; or accept Withdraw(X : Integer) do A.Balance := A.Balance - X; end Withdraw; or accept Quit do Stop := True; end Quit; end select; end loop; end Banker; Myaccount : Accountptr; Mybanker : Banker; -- the banker thread, waiting for "setaccount" X : Integer; begin -- body of main procedure will provide the client thread Myaccount := Makeaccount(1000); Mybanker.Setaccount(Myaccount); -- banker enters into server loop Mybanker.Withdraw(400); Mybanker.Deposit(600); Mybanker.Inquiry(X); Put("my balance is now "); Put(X,Width=>6); New_Line; Mybanker.Quit; end Concbank; -- In this program there is only one "client" task: the main body of -- the "concbank" procedure. There is really no critical section problem -- unless two or more client tasks tries to invoke transactions on the -- same banker task. -- This may seem like a neat program but there are several problems that are -- not addressed. -- First, not only could there be several client tasks to a single banker, -- but also several different bankers could manage the same bank account! -- (by sending them pointers to the same account via setaccount). This means -- that two bankers could be trying to change the balance of an acount at the -- same time, creating a "critical region". So this program only "works" if -- we can guarantee that there is only one banker for each account. One way -- to accomplish this would be to have "makeaccount" also be an entry inside -- the banker task, so that the entire account record is kept as a local -- structure inside the banker task. -- Secondly, we'd like it so that if a client tries to withdraw an -- amount greater than the balance, the withdraw thread should block until -- enough funds are available. That is, say my balance is $500 and I write -- a check for $600. The transaction will be put on hold. In the main time, -- another thread (say automatic deposit from my employer) deposits $1000 -- into my account a short while later. The suspended withdraw transaction -- should now be allowed to continue. This is better than bouncing the -- check right away, is it not? How do we code this? -- go to the next program.