We'll wait a second between printing each line of text, which will help you see what it does. To make it more interesting, we'll include in the Start request the message to be printed and the number of times it's to print.
First, let's create a task type; the task type will be called Babbler, and we'll enclose it in a package called Babble. Its declaration could look like the following:
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; package Babble is task type Babbler is entry Start(Message : Unbounded_String; Count : Natural); end Babbler; end Babble;
When declaring a task, an "entry" is somewhat analogous to a procedure declaration. An entry statement declares what requests may be made to the task, including what information may be sent to and from the task when the request is made.
Just like packages and subprograms, tasks have a declaration and a body. The task body could look like this:
with Ustrings; use Ustrings; package body Babble is task body Babbler is Babble : Unbounded_String; Maximum_Count : Natural; begin accept Start(Message : Unbounded_String; Count : Natural) do Babble := Message; -- Copy the rendezvous data to Maximum_Count := Count; -- local variables. end Start; for I in 1 .. Maximum_Count loop Put_Line(Babble); delay 1.0; -- Wait for one second. end loop; -- We're done, exit task. end Babbler; end Babble;
A task body defines what the task will do when it is started up. This particular task simply sets up some local variables and then runs an "accept" statement. An "accept" statement waits for some other task to make a request via the corresponding "entry". When another other task makes the matching request, the accepting task runs the accept statements between the word "do" and the "end" that matches the accept statement. When a task is running the accept statements between "do" and "end", it is said to be in a rendezvous with the other task; the requesting task will not run any instructions until the "end" of the accept statement is run. A common task done in a rendezvous is to copy the data sent by the sending task to a place where the receiving task can use it later. Once the rendezvous is complete, both tasks can run.
Here's a short procedure to demonstrate this task type; we'll call it the procedure Noise. Noise will create two tasks of the given task type and send them Start messages. Note how similar creating a task is to creating a variable from an ordinary type:
with Babble, Ustrings; use Babble, Ustrings; procedure Noise is Babble_1 : Babbler; -- Create a task. Babble_2 : Babbler; -- Create another task. begin -- At this point we have two active tasks, but both of them -- are waiting for a "Start" message. So, send them a Start. Babble_1.Start(U("Hi, I'm Babble_1"), 10); Babble_2.Start(U("And I'm Babble_2"), 6); end Noise;
A procedure that declares a task instance, like procedure Noise, is called a Master. A master must wait for all its tasks to terminate before it can terminate, so Noise will wait until Babble_1 and Babble_2 have exited before it exits.
Note that when procedure Noise makes a ``call'' to Babble_1 and Babble_2's `Start' entry, it is performing a rendezvous.
Should you see the lines of text from Babble_1 and Babble_2 interleaved on your display when you run Noise?
|Go back to the previous section||Skip to the next section||Go up to lesson 13 outline|
David A. Wheeler (email@example.com)
The master copy of this file is at
The master copy of this file is at "http://www.adahome.com/Tutorials/Lovelace/s13s2.htm".