Private entries and entry families

Một phần của tài liệu Burns, wellings concurrent and real time programming in ada (Trang 155 - 158)

Messages_On_Tape : Natural := 0;

end Answering_Machine;

procedure Call(M : Message) is begin

select

Client.Call(M);

or

delay Timeout_On_Client;

select

Answering_Machine.Call(M);

or

delay Timeout_On_Answering_Machine;

raise Not_Operational;

end select;

end select;

exception

when Tasking_Error => -- client no longer callable raise Not_Operational;

end Call;

protected body Answering_Machine is entry Call(M : Message)

when Messages_On_Tape < Max_Messages is begin

Messages_On_Tape := Messages_On_Tape + 1;

-- put message on Tape end Call;

procedure Replay(MS : out Message_Set) is begin

-- rewind Tape MS := Tape;

Messages_On_Tape := 0;

end Replay;

end Answering_Machine;

task body Client is separate;

-- includes calls to Answering_Machine.Replay end Telephone;

Note that this example makes use of a timed entry call on a protected entry.

The semantics of this feature are identical to those of a timed entry call on a task.

Conditional entry calls can also be made.

7.5 Private entries and entry families

So far this chapter has considered the basic protected type. As with tasks, protected objects may have private entries. These are not directly visible to users of the protected object. They may be used during requeue operations (see Chapter 8).

A protected type can also declare a family of entries by placing a discrete subtype definition in the specification of the entry declaration. Unlike task entry families, however, the programmer need not provide a separate entry body for each member of the family. The barrier associated with the entry can use the index of the family (usually to index into an array of booleans). Consider the following:

type Family is Integer range 1 .. 3;

protected Controller is entry Request(Family)(...);

end Controller;

task Server is

entry Service(Family)(...);

end Server;

In the case of theServertask it is necessary, inside the body of the task, to execute an accept statement naming each member of the family. For example, to wait for a request from any member requires a select statement:

task body Server is begin

...

loop select

when Some_Guard_1 =>

accept Service(1)(...) do ...

end Service;

or

when Some_Guard_2 =>

accept Service(2)(...) do ...

end Service;

or

when Some_Guard_3 =>

accept Service(3)(...) do ...

end Service;

end select;

...

end loop;

end Server;

For the protected body, it is not necessary to enumerate all the members of the family (indeed, the programmer is not allowed to do so). Instead, a shorthand notation is provided:

protected body Controller is

entry Request(for I in Family )(...) when Some_Barrier_Using(I) is

7.5 Private entries and entry families 141 begin

...

end Request;

end Controller;

This is notionally equivalent to -- Not Valid Ada

protected body Controller is

entry Request(1)(...) when Some_Barrier_Using(1) is begin

...

end Request;

entry Request(2)(...) when Some_Barrier_Using(2) is begin

...

end Request;

entry Request(3)(...) when Some_Barrier_Using(3) is begin

...

end Request;

end Controller;

For example, the following defines a protected type which provides a group com- munication facility. The typeGroupdefines several communications groups. The protected procedure Send transmits a Data Item to a particular group. The family of entriesReceiveallows a task to wait for aData Itemon a particular group:

type Group is range 1 .. 10;

type Group_Data_Arrived is array(Group) of Boolean;

protected type Group_Controller is procedure Send(To_Group : Group;

This_Data : Data_Item);

entry Receive(Group)(Data : out Data_Item);

private

Arrived : Group_Data_Arrived := (others => False);

The_Data : Data_Item;

end Group_Controller;

My_Controller : Group_Controller;

protected body Group_Controller is

procedure Send(To_Group : Group; This_Data : Data_Item) is begin

if Receive(To_Group)’Count > 0 then Arrived(To_Group) := True;

The_Data := This_Data;

end if;

end Send;

entry Receive(for From in Group)(Data : out Data_Item) when Arrived(From) is

-- this is a family of entries begin

if Receive(From)’Count = 0 then Arrived(From) := False;

end if;

Data := The_Data;

end Receive;

end Group_Controller;

When a task sends data to a particular group, theSendprocedure looks to see if any tasks are waiting on theReceiveentry for that particular member of the family. If tasks are waiting, it sets a boolean flag associated with the member to true. On exit from the procedure, the barriers associated with theReceive family entries are re-evaluated. The appropriate group’s boolean evaluates to true and so that entry of the family is open. The entry body is executed and, if only one task is waiting, the boolean is set to false; in either case the data is sent to the first queued task. If the guard is still open, the entry body is executed again, and so on until all tasks queued for the group are released with the multi-cast value. Note that, once a task is executing inside the protected object, no other task can join an entry queue or be removed from an entry queue.

There are other ways of manipulating the barrier on the entry family (for exam- ple saving the identifier of the group during the Sendoperation and comparing the family index with the group identifier). However, the given solution is easily extendible if the message is to be sent to more than one group.

It is useful to dwell on one further feature of the above code. In general, a call ofSendmay release blocked tasks onReceive. But it cannot just set the barrier to true on Receive: it must first check to see if any task is blocked (using the

’Countattribute). Moreover, the last task to be released must set the barrier again to false. These checks must be made, as a change to a barrier value is persistent.

This can be compared with a signal on a monitor’s condition variable (see Chapter 3), which has either an immediate effect or no effect at all.

Một phần của tài liệu Burns, wellings concurrent and real time programming in ada (Trang 155 - 158)

Tải bản đầy đủ (PDF)

(477 trang)