Bank Demo 3, or BD3 as the files and mainline procedure are named, is ademonstration program which illustrates how Ada and its tasking mechanism can beused to create a model of an activity in the real world. BD3 is a model of abank, where the bank contains several tellers, implemented as Ada tasks, and isused by customers, also implemented as Ada tasks. The user at the console canmonitor the status of the bank and the accounts of its customers and cause morecustomer tasks to execute, thereby increasing the level of activity at the bank.The tasks all operate in parallel, so a variety of events can be thought of ashappening at the same time, controlled by the Ada runtime system which is builtinto the Ada program by the Ada compilation system.
This document and the associated software are presented as an introductionto the Ada language and its tasking capabilities. While the author attempted tomake this document as easy to follow as possible, a limited knowledge of Ada isassumed. Variable assignments, type definitions, and procedure and packagespecifications are presented in correct Ada syntax without much explanation. Ifthis proves to be a problem, the ADA-TUTR shareware program will help a lot inbringing the user up to date with an understanding of Ada syntax. Regardless,the program in the file BD3.EXE can be run without any knowledge of Ada at all,and the tasking demonstration can be observed.
SET page=1
BEGIN HEADER
BD3 - A Demonstration of Tasking in Ada
END HEADER
BANK DEMO 3
A Demonstration of Tasking in Ada
by Richard Conn
RESERVE 4
SECTION Introduction
BD3 is a model of a bank. The Ada package called BANK represents the bankitself, and the bank contains four tellers, represented by an array, namedTELLER, of four tasks. BD3 is written in an object-oriented fashion in the Adaprogramming language.
Each task, TELLER(1) to TELLER(4), supports one entry point, calledREQUEST, which is used by tasks outside the BANK package to communicate with aTELLER(n) task and request a transaction. Four transaction requests arerecognized by a TELLER(n) task, as shown in Figure TRANSACTION.
Each TELLER(n) task performs one of these four transactions at a time. Anexternal task calls (makes a rendezvous with, in Ada terminology) a TELLER(n)task through its REQUEST entry point, passing one of these transaction names asa parameter, and the TELLER(n) task processes the request. For example, a codesegment in an external task may look something like Figure CALLTELLER. Thiscode segment was extracted from the body of the CUSTOMER task definition in thepackage CUSTOMER_WORLD (see later).
This demonstration program also contains several other tasks, calledcustomer tasks. These tasks, hidden inside the package CUSTOMER_WORLD, operateindependently and interact with the various teller tasks. The customer tasksmake requests to the teller tasks, asking to be added as a customer of the bank,making deposits, and making withdrawals. Using the Ada inter-task rendezvousmechanism to communicate, if the teller task is already servicing anothercustomer task, the customer task "waits in line" (having been placed in theimplicit queue associated with the teller's entry point). If queued, thecustomer task is serviced after the tasks in the teller's queue in front of himhave been serviced. Indeed, the model is similar to the real world.
From the mainline procedure, the user can monitor the bank and itsactivity. He can obtain a status report from the bank (which includes thebalanace of each customer, the number of transactions requested by eachcustomer, and the number of transactions processed by each teller), cause newcustomer tasks to start up, and shut down the system and exit the program. Forthose Ada compilers which do not allow tasking to proceed while the current taskis waiting for input (such as many of the Ada compilers available for the IBMPC), a continuous display function is also provided to the user which displaysthe bank's status, delays five seconds (allowing the various tasks to run), anddisplays the bank's status again. This command option displays ten statusreports before returning the user to his prompt.
RESERVE 4
SECTION Execution of the Program
Figures EX1 to EX7 show various displays during the execution of theprogram. These displays were generated on a SUN workstation, where the programwas compiled by the Verdix Ada compiler. These displays may be different fromwhat you see if you compile the program on an IBM PC, particularly in thatVerdix Ada does not suspend all tasks while the current task is waiting forinput from the console. While we are at the prompt in these figures, all tasksare running in parallel with our input activity. On some compilers this willnot be the case, and the parallel operation of the tasks will not be seen untilthe user issues the 'c' (continuous bank status) command.
Figure EX2 shows the start of the first customer task via the 's' commandfollowed immediately by a status report of the bank (requested via the 'b'command). The task we just started has had enough time between the start of thetask and the request of the status display to perform 2 transactions, and we cansee that tellers 2 and 3 were selected to perform these transactions.
Figure EX3 shows another bank status command, which was issued as soon asthe display above completed. During this brief amount of time, the customer hashad time to perform another transaction.
Five more customer tasks are started up in Figure EX4 and another bankstatus display is requested. The fact that we have many tasks running inparallel now should become evident as we see more and more activity going onbetween each of our status displays.
Figure EX5 shows a 'c' (continue bank status) command and its resultingdisplay. To save space, I have shown only the first and the last of the elevenbank status report displays generated by this command.
In Figure EX6, two more customer tasks are started and the result is shown. There are now 8 customer tasks, 4 teller tasks, and the mainline procedure (asanother task) running in this Ada system.
Figure EX7 shows two more bank status displays. The user of the programhas delayed for some time before issuing these commands so that a significantlevel of activity can be shown.
More activity could be displayed, and more customer tasks could be started,but the displays shown so far should be enough to give the reader a good feelfor the program's operation. When the user is finished, the 'x' (for exit)command will terminate all tasks and return the user to the operating system.
The displays presented so far were generated by the BD3 mainline procedurerunning on a UNIX system, having been compiled by the Verdix Ada compiler. BD3.EXE provided in the distribution was compiled under the IntegrAdaenvironment. The reader will see similar displays when BD3.EXE is executed withthe exception that no other tasks will run when the prompt is displayed. Inorder for multitasking to be observed when running BD3.EXE, the user must issuethe 'c' (for continuous bank status) command. Once the delay statement in themainline is encountered, the Ada runtime system is allowed to come into play andother tasks are then permitted to run.
RESERVE 4
SECTION Discussion of the Design
BD3 is an object-oriented design. The objects contained in this Ada systemare a console device (defined by the Ada package CONSOLE) which supports inputand output from and to the user's console terminal, a random number generator(defined by the Ada package RANDOM) which generates random numbers of type FLOATin the range from 0.0 to 1.0, the bank (defined by the Ada package BANK) whichcontains the four TELLER(n) objects (defined by the Ada task type TELLER_PERSON)and the basic type definitions (such as TRANSACTION, CUSTOMER_ID, and DOLLAR)which are used to communicate with a TELLER(n) object, and the base of customers(defined by the Ada package CUSTOMER_WORLD) which interacts with the tellers inthe bank.
The specification to the package CONSOLE is shown in Figures CONSOLE1,CONSOLE2, and CONSOLE3. Each line is numbered for the convenience of the reader(of course, these numbers do not appear in the files which are compiled by anAda compiler).
In Figure CONSOLE1, the prologue in the specification of the packageCONSOLE is given. Line 1 is the only piece of processed code; the rest of thelines are Ada comments which describe the package and give other informationabout it. I developed this package some time ago for use in my Ada classes,feeling that the package TEXT_IO (which is supplied with all Ada compilers) istoo complex for most beginners to work with. Package CONSOLE starts tointroduce an object-oriented design to Ada code design and is simple to use.
Figure CONSOLE2 contains more of the specification of package CONSOLE,showing the two type definitions used by procedures within the package and fourprocedure specifications, all for procedures named WRITE (see lines 39, 40, 48,and 58). These procedures, all similarly named, differ in the types ofarguments they accept, and Ada determines which procedure is reference by thetypes of the arguments used when the call to the procedure is made. The commentblocks in lines 41-46, 49-53, and 59-65 contain examples of how these procedureswould be called from outside of package CONSOLE.
Note that the WRITE procedure on line 58 accepts two parameters, an INTEGERand a NATURAL number with a default value. The default value of 0 for the WIDTHparameter tells the procedure to use as many spaces as necessary to output thenumber. As indicated by lines 63-65, the WIDTH parameter does not have to bereferenced when the procedure is called.
Figure CONSOLE3 contains the next part of the specification for packageCONSOLE. Lines 67-69 define the specification for a WRITE procedure which workson objects of type FLOAT (floating point) to output them in the form "nn.nn"while lines 70-71 define the specification for a WRITE_SCIENTIFIC procedurewhich also works on objects of type FLOAT but outputs them in scientificnotation.
Figure CONSOLE4 shows the last part of package CONSOLE. Procedure READ online 85 always returns an object of type OUTSTRING, which is 80 characters long. When this procedure is called, the next line typed by the user is returned. Ifit is less than 80 characters long, trailing spaces are appended to it. If itis more than 80 characters long, the first 80 characters are returned and thenext call to READ returns the next 80. For the convenience of the user, thefunction TRIM (line 93) is provided to convert a string of any length to one ofanother length that contains all characters of the input string except thetrailing spaces.
The random number generator object used by the Bank Demo Ada system isdefined by the Ada package named RANDOM. Figure RANDOM contains thespecification of this package. RANDOM contains only one function, named NUMBER,which requires no input parameters and returns the next random number as anobject of type FLOAT. A code segment like the one in Figure RANDOMS is used tocall the NUMBER function in package RANDOM:
If you look at the body of package RANDOM, which is included in the sourcecode distributed with Bank Demo, you will find that RANDOM contains a hiddenprocedure called SEED that sets the first random number in the sequence based onthe time-of-day clock value returned by the Ada-standard package calledCALENDAR. Procedure SEED, however, is not needed by the outside world, sopackage RANDOM does not make it available.
Figure BANK1 contains the prologue of the specification of package BANK,which defines the bank object. Note that the tellers are implemented as tasks(I refer to the tellers in a general sense as TELLER(n), where n is 1 to 4 toindicate which teller).
Figure BANK2 shows more of the specification of package BANK. The typedefinitions are presented first. Lines 25-28 define type TRANSACTION, which arethe transactions which may be requested of a TELLER(n) object. The transactionswhich may be performed by a teller are ADD_NEW_CUSTOMER, GET_BALANCE,MAKE_DEPOSIT, and MAKE_WITHDRAWAL. Line 31 defines type DOLLAR, which is theunit of currency for the bank. DOLLAR is implemented as a floating pointnumber, derived from type FLOAT, but DOLLAR objects are unique from FLOATobjects by this type definition (DOLLAR is a derived type in Ada) and we cannotinterchange the use of a DOLLAR object and a FLOAT object. Line 34 defines typeCUSTOMER_ID, which is the ID number associated with each customer. When atransaction is made with a teller, the customer presents his ID number toidentify himself along with his transaction request. Like DOLLAR, CUSTOMER_IDis a derived type, but CUSTOMER_ID is derived from type NATURAL and can take onvalues from 1 to NATURAL'LAST (the largest value allowed for objects of typeNATURAL).
In Figure BANK3, line 37 defines type TELLER_INDEX, which is used toidentify the desired teller. Type TELLER_INDEX is derived from type NATURAL andrestricted in range from 1 to 4. If the user wishes to modify this program andadd more tellers to the model, he need only change the 4 on line 37 to thedesired number. The parts of the code which need to know how many tellers areavailable at the bank reference TELLER_INDEX'LAST, which is the largest valuethat objects of type TELLER_INDEX can take on.
Task type TELLER_PERSON on lines 42-46 defines the interface to all tasksof type TELLER_PERSON. A TELLER_PERSON task contains one entry point, calledREQUEST, which can be called by tasks external to package BANK. Threeparameters must be specified when the REQUEST entry point is called: the ID ofthe customer (type CUSTOMER_ID), the KIND of transaction (type TRANSACTION), andthe AMOUNT associated with the transaction (type DOLLAR).
The task body of TELLER_PERSON is not contained in the specification ofpackage BANK, but it is hidden in the body of package BANK. You can see thiscode by looking at the source code provided in the distribution. In summary,tasks of type TELLER_PERSON are quite simple in their operation. When a task oftype TELLER_PERSON starts running, it calls the internal task TELLER_ASSIGNER(which is hidden inside of package BANK) in order to get its ID number. As eachcustomer has an ID, so each teller also has an ID. The teller's ID is used tokeep a running record of the number of transactions each teller makes. After itgets it's ID number, a task of type TELLER_PERSON enters an infinite loop inwhich it waits for an external task to call its REQUEST entry point, processesthe request from this external task based on the KIND of transaction requested,and then resumes the loop. It is left as an exercise to the reader to read thecode and figure out exactly what happens for each KIND of transaction.
Line 48 defines the array, named TELLER, of tellers in the bank. Eachelement of this array is of type TELLER_PERSON, making each element anindependent task as opposed to what the reader may normally think of as an array(which is an array of values stored in memory). The array TELLER is indexed byTELLER_INDEX, taking on index values from 1 to 4. Hence, four tasks are createdby the array declaration on line 48: TELLER(1), TELLER(2), TELLER(3), andTELLER(4). Each task starts running during initialization of the Ada system before the first line of code of the mainline procedure is executed.
Package BANK also exports two procedures, as shown in Figure BANK4:PRINT_REPORT and STOP_WORK. PRINT_REPORT (whose specification is on line 52)prints a report of the status of the bank. This report indicates the number oftransactions requested by each customer, the balance of each customer's account,and the number of transactions processed by each teller. These items ofinformation are updated constantly by the TELLER(n) tasks by means of a database kept internal to package BANK. The outside world does not need to knowthat this data base exists or what form it exists in; the outside world onlyneeds to know that it can print this report based on information in the database. PRINT_REPORT is called by the BD3 mainline procedure whenever the user atthe console asks for it or during the running of the continuous status displaycommand issued by the user. STOP_WORK (whose specification is on line 55)terminates all of the TELLER(n) tasks. STOP_WORK is called by the BD3 mainlineprocedure when the user asks for the program to shut down (the exit command). All tasks of the Ada system must be terminated before the mainline procedure,which is also a task, may terminate. STOP_WORK represents a function that wouldbe performed by a bank when it closes and it is reasonable to provide it as partof the specification of package BANK as opposed to relying upon the mainlineprocedure to abort each of the TELLER(n) tasks on a task-by-task basis.
Figure CUSTOMER contains the specification of the package CUSTOMER_WORLD. This package contains, hidden within it, all of the customer tasks which arerunning in the system. Internally, package CUSTOMER_WORLD keeps track of thesetasks by creating a linked list which points to each of them. The procedure ADD(whose specification is on line 308) causes the package CUSTOMER_WORLD to spawnanother customer task, updating the linked list when it does so. When eachcustomer task is spawned, it begins running immediately, performing thefunctions of an independent customer. There are no entry points to a customer;the outside world does not request access to a customer, and the customer taskseach act independently of each other, requesting access to the TELLER(n) tasksin the bank to perform transactions as they need them. Each time the userissues the "start new customer" command from the console, procedureCUSTOMER_WORLD.ADD is called to perform this function, and a new customer taskstarts running.
As mentioned in the discussion of package BANK, all children tasks have tobe aborted before the mainline procedure can terminate, and packageCUSTOMER_WORLD exports the procedure TERMINATE_ALL to do this. TERMINATE_ALLmoves through the linked list of tasks, aborting each one as it is encountered. The BD3 mainline procedure calls CUSTOMER_WORLD.TERMINATE_ALL just like it callsBANK.STOP_WORK when the exit command is processed.
The task specification and body of a customer (the task type is namedCUSTOMER) is hidden in the body of package CUSTOMER_WORLD. Each customer taskperforms the following sequence of operations:
1. The customer selects a TELLER(n) task at random using the random numbergenerator (function NUMBER in package RANDOM). The customer issues anADD_NEW_CUSTOMER transaction through the REQUEST entry point of the selectedTELLER(n) task. The selected TELLER(n) task returns the customer task's IDnumber, which the customer task stores for use on all future transactions withall TELLER(n) tasks.
2. The customer, using his ID number, then selects a TELLER(n) task at randomand issues a MAKE_DEPOSIT transaction through that teller's REQUEST entry point. The customer deposits $100.00 (see lines 325 and 379-380 in the full listing ofBD3 distributed with this document).
3. The customer now enters an infinite loop, which he stays in for the rest ofhis life (until he is aborted by the user at the console issuing the exitcommand). This loop (see lines 389-399 of the source listing) consists of thefollowing steps:
3.1. Delay a random amount of time from 0 to 5 seconds.
3.2. Generate a random amount of money from -$50.00 to $50.00. If the amountis negative, select the current transaction to be MAKE_WITHDRAWAL and make theamount positive. If the amount is positive, select the current transaction tobe MAKE_DEPOSIT.
3.3. Select a TELLER(n) task at random, call that teller's REQUEST entrypoint, passing to it the his ID number, the desired transaction, and the amount. The TELLER(n) task will then process the transaction, allowing a withdrawal onlyif the customer has sufficient funds to cover the request.
Figures BD1 to BD4 contain the source code of the mainline procedure forthis Ada system, procedure BD3 (short for Bank Demo 3). This procedure is wherethe execution of the mainline begins. All tasks which were declared staticallyas objects, such as the TELLER(n) tasks of package BANK, will have already beeninitialized and begun execution before the first line of this procedure isexecuted. The customer tasks will be dynamically created during the executionof this procedure, where a new customer task will be created each time the userissues the "start next customer" command from the console.
In Figure BD1, lines 442-444 establish the context in which the procedurefunctions. In particular, the procedure BD3 needs to know about package BANK,package CUSTOMER_WORLD, and package CONSOLE. These Ada packages must bepreviously compiled into the current program unit library before procedure BD3can be compiled. The Ada compiler will check all interfaces (such as procedureand object names, parameters passed to the procedures, and the types of allobjects referenced) between these packages and procedure BD3 each time BD3references one of these packages.
Line 445 introduces the procedure (is the beginning of procedure BD3'sbody), and the rest of the lines in Figure BD1 are comments in the prologue.
Figure BD2 shows a local variable and a local constant in procedure BD3. The variable INPUT is used to receive the line entered by the user when he isprompted for input. The READ procedure in package CONSOLE is used to input thisline. The definition of the constant number of continuous status reports isself-explanatory.
Figure BD3 shows the beginning of the executable code in procedure BD3. This code starts after the "begin" statement on line 486, and the entirety ofthis code is contained within the loop which starts on line 493.
The first thing done in this loop is the presentation of the prompt to theuser (lines 496-504) and the input of the command from the user (line 505).
Figure BD4 shows the rest of procedure BD3. The first letter of thecommand just input (line 505 of Figure BD3) is the target for the caseexpression in line 508. If this letter is a lower-case 'b' (bank status) or 'c'(continuous bank status), the code in lines 509-519 will be executed. If thisletter is a lower-case 's' (start next customer), the code in lines 520-522 willbe executed. If this letter is a lower-case 'x' (exit), the code in lines523-527 will be executed. If this letter is a space, nothing happens (lines528-530). If this letter is anything else, an error message is printed (lines531-535). The loop itself ends on lines 538, and the procedure BD3 ends on line540.
RESERVE 4
SECTION File Distribution
Figure FILELIST shows the files provided in the distribution of Bank Demo3. This document is in one-column format in the file PRINT.ME.