-- this program is a very simple example of a server task serving -- a client task -- Conceptually, one can think of a task as a kind of running object. -- An entry point, on which a task can perform an accept, has the syntactic -- structure of a regular procedure, but should be distinguished from one. -- An accept statement is more like a synchronization point at which the -- called task and the calling task can exchange information via the entry's -- formal parameters. The code of the accept-do -- construct is executed by the called task that the accept statement belongs -- to. This is in contrast to other synchronization models just as found -- in Java (or with Ada's own "protected types"), where the body of a -- synchronized procedure is executed by the calling task. -- When a task calls accept, it waits (suspends execution) until some other -- task calls the entry point. Likewise, a task calling the entry point of -- another task will block until the other task executes accept. This is the -- basic synchronization mechanism of Ada. -- Often, a task defines multiple entries. Since other tasks may call these -- entries in any order, there needs to be a way to demultiplex -- entry calls. That is, a way to say "accept EITHER entryA OR entryB". This -- is the purpose of the "select" construct. Select is to concurrent -- programming what an if-else or switch construct is to conventional -- programming. -- A related ability (not shown in example) is the "select else" construct: -- select -- accept entryA(...) do ... -- ... -- else -- ... -- end select; -- such a construct will execute the else part in case there is no pending -- call to entryA. That is, it will accept entries WITHOUT BLOCKING. This -- is another example of asynchronous operation. -- Yet another refinement of select is the "when" construct, which we -- can put in front of accepts. -- select -- when (x<0) => -- accept entryA(...) do ... -- ... -- or -- when (x>=0) => -- accept entryB(...) do ... -- ... -- end select; -- As such an select statement is executed, then boolean conditions in the -- "when" constructs are all evaluated, and only the cases that evals to -- true will be considered as part of the select; the others are ignored. -- Sample program: let's serve fibonacci numbers! with Text_IO, Ada.Integer_Text_IO; use Text_IO, Ada.Integer_Text_IO; procedure Conc2 is type Fibar is array(0..1000) of Integer; task fibServer is entry Reset; entry stop; entry Getfib(X : out Integer); end fibServer; task type FibClient(ClientID : Character); -- bodies of task and task types: task body fibServer is Quit : Boolean := False; Knownfibs : Fibar; temp : Integer; Lastfib, curfib : Integer; Lastknown : Integer := 1; begin Knownfibs(0) := 0; Knownfibs(1) := 1; lastfib := 0; curfib := 1; while not(Quit) loop select -- sleep until one of the following entries is called: accept Reset do Lastknown := 1; end Reset; or accept Stop do Quit := True; end Stop; or accept Getfib(X : out Integer) do X := Curfib; end Getfib; Temp := Curfib; Curfib := Lastfib + Curfib; Lastfib := temp; end select; end loop; end fibServer; ------------------------------- task body FibClient is I, N : Integer; begin -- let's get lots of fibonacci numbers! I := 0; while (I < 500) loop FibServer.Getfib(N); Put("I'm client "); Put(Clientid); Put(" and I got a fib number:"); Put(N,Width=>1); New_Line; delay(0.25); -- delay for 1/4 seconds real time (approx!) I := I+1; end loop; end FibClient; Ca : FibClient('A'); Cb : FibClient('B'); Cc : FibClient('C'); begin -- start of conc2 main procedure Put("1 server and 3 clients started;"); New_Line; delay(5.0); Fibserver.stop; end Conc2;