From: "Hibou57 (Yannick Duchêne)" <yannick_duchene@yahoo.fr>
Subject: Re: Private or public task ?
Date: Fri, 5 Feb 2010 12:56:13 -0800 (PST)
Date: 2010-02-05T12:56:13-08:00 [thread overview]
Message-ID: <e95a61c0-f1ed-4f08-96b9-32e969d9115b@3g2000yqn.googlegroups.com> (raw)
In-Reply-To: a35584dd-8693-484d-918d-758940dccfe8@d37g2000yqa.googlegroups.com
The source I'm referring to in the previous post :
with Ada.Text_IO;
-- For the service provided by the
-- Output_Server package.
with Ada.Finalization;
-- For the Ticket_Type implementation.
procedure Test is
package Text_IO renames Ada.Text_IO;
package Output_Server is
-- Provides a server which outputs text on
-- the standard output stream, in an atomic
-- maner. Ths purpose of this package is
-- to experiment and the better implementation
-- for such a requirement, would have been to
-- simply use a protected type. This is an
-- experiment to do the same with a task
-- instead.
type Ticket_Type is limited private;
-- Any request to Instance.Put must be
-- made providing a ticket. The Instance task
-- will live at least as long as a ticket
-- is alive in scope and as long as there is
-- no more ticket alive.
task Instance is
entry Put
(Ticket : in Ticket_Type;
Text : in String;
Number : in Natural);
-- Print Text follow by the image of Number
-- on a new line on the standard output. Keep
-- in mind this is just an experiment example.
--
-- The normal way to complete a task in Ada
-- (not to be confused with task termination),
-- is to either have executed all of its task
-- body [ARM 9.3(5)] or to be blocked on select
-- statement with an opened terminate alternative
-- [ARM 9.3(6/1)], that is, if there is no other
-- opened accept statement matching a queued
-- request [ARM 9.7.1(16)] (providing the task
-- body is built around a Select Accept block).
--
-- The "trouble" with this, is that this will
-- be completed as soon there will be no more
-- queued request pending. Indeed, the task
-- semantic refer to actual state and in some
-- way to the previous state, but cannot refer
-- to any futur or potentially futur state.
--
-- We want to complete the task, only when we
-- will know no futur request could come.
-- A specification may be to tell we are in
-- such a case when no more client task are
-- alive (when they are either all completed
-- or terminated).
--
-- So we need a way to know which tasks are
-- clients of this server task. This is the
-- purpose of the ticket of Ticket_Type which
-- comes as a required parameter of the Put
-- entry.
end Instance;
private
-- There use to be an implementation where
-- the server task exposed an Acquire and
-- Release entry, which client were to invok
-- to declare they are client and later no
-- more client of the server task. To
-- be more secure, it was later decided to
-- manage it automatically via the
-- Initialize/Finalize capabilities of a
-- Limited_Controlled type.
--
-- Clients do not invok any more Acquire
-- and then later Release, they just have
-- to own a ticket, which automatically
-- do the stuff as its initialization
-- and later finalization part. This
-- is more safe and less error prone
-- on the client side.
type Ticket_Type is
limited
new Ada.Finalization.Limited_Controlled
with null record;
overriding procedure Initialize
(Ticket : in out Ticket_Type);
-- Initialization of a ticket register
-- a client.
overriding procedure Finalize
(Ticket : in out Ticket_Type);
-- Finalization of a ticket unregister
-- a client.
end Output_Server;
package body Output_Server is
-- Ticket_Type is a private type of the
-- Output_Server package. It needs to
-- inform the Instance task (the server
-- task) when a ticket is entering into
-- existance and when it is later no
-- more alive.
--
-- Unfortunately, we cannot provide Acquire
-- and Release entries which will be only
-- accessible to the implementation of
-- Ticket_Type.
--
-- So, we need another way the Ticket_Type
-- and the Instance to be able to communicate
-- privately. This is done via the following
-- Clients_Counter protected object.
protected Clients_Counter is
procedure Acquire;
procedure Release;
function Count return Natural;
function Has_Started return Boolean;
private
-- These two members use the postffix _Value
-- to avoid a name clash with the two
-- corresponding functions.
Count_Value : Natural := 0;
Has_Started_Value : Boolean := False;
-- The number of registered clients is first
-- zero. The Instance task completes as soon
-- as there is no queued request and the number
-- of living registered clients is zero.
--
-- But the start time is a special case : we
-- are waiting for client to register. So
-- we will not consider the first zero value,
-- and will only take care of a zero value
-- when it will go down to zero.
--
-- This is the purpose of Has_Started_Value.
--
-- Thus, the Instance task can request to
-- both Count and Has_Started status.
end Clients_Counter;
protected body Clients_Counter is
procedure Acquire is
begin
Has_Started_Value := True;
Count_Value := Count_Value + 1;
Text_IO.Put_Line
("Acquire: Count is now " &
Natural'Image (Count_Value) &
"and Has_Started is now " &
Boolean'Image (Has_Started_Value));
-- Log Clients_Counter activities for
-- debuging purpose.
end Acquire;
procedure Release is
begin
Count_Value := Count_Value - 1;
Text_IO.Put_Line
("Release: Count is now " &
Natural'Image (Count_Value));
-- Log Clients_Counter activities for
-- debuging purpose.
end Release;
function Has_Started return Boolean is
begin
-- {Location #1}: if this log
-- statement is removed, then
-- the Instance task blocked
-- indefinitely at location #2.
Text_IO.Put_Line
("Has_Started: returned " &
Boolean'Image (Has_Started_Value));
-- Log Clients_Counter activities for
-- debuging purpose.
return Has_Started_Value;
end Has_Started;
function Count return Natural is
begin
Text_IO.Put_Line
("Count: returned " &
Natural'Image (Count_Value));
-- Log Clients_Counter activities for
-- debuging purpose.
return Count_Value;
end Count;
end Clients_Counter;
overriding procedure Initialize
(Ticket : in out Ticket_Type)
-- Initialization of a ticket register
-- a client.
is
begin
Clients_Counter.Acquire;
end Initialize;
overriding procedure Finalize
(Ticket : in out Ticket_Type)
-- Finalization of a ticket unregister
-- a client.
is
begin
Clients_Counter.Release;
end Finalize;
task body Instance
is
begin
while True loop
select
accept Put
(Ticket : in Ticket_Type;
Text : in String;
Number : in Natural)
do
pragma Unreferenced (Ticket);
-- The sole use of the ticket is
-- to require the client to actually
-- own a ticket.
Text_IO.Put_Line
(Text &
" " &
Natural'Image (Number));
end Put;
or
-- {Location #2}: this work find
-- as long a there is a log statement
-- at location #1. If this statement
-- is removed, then the task never
-- reach its terminate alternative.
when
(Clients_Counter.Has_Started) and
(Clients_Counter.Count = 0)
=>
terminate;
end select;
end loop;
end Instance;
end Output_Server;
-- Shortcuts for better readability.
subtype Ticket_Type is
Output_Server.Ticket_Type;
procedure Put
(Ticket : in Ticket_Type;
Text : in String;
Number : in Natural)
renames
Output_Server.Instance.Put;
-- Keep in mind it's a task entry.
-- Now comes three simple task.
-- Al have the same layout. The
-- first one is the sole commented
-- one.
task First_Task;
task body First_Task
is
Ticket : Ticket_Type;
-- Automatically register this
-- task as client when we enter the
-- scope and unregister this task
-- when the task is terminated.
begin
for Index in 1..4 loop
Put
(Ticket,
"This is First_Task, passing number ",
Index);
-- Remember Put is a request to the
-- Output_Server.Instance.Put entry.
end loop;
end First_Task;
-- Second task : same thing.
task Second_Task;
task body Second_Task
is
Ticket : Ticket_Type;
begin
for Index in 1..7 loop
Put
(Ticket,
"This is Second_Task, passing number",
Index);
end loop;
end Second_Task;
-- Third task : same story.
task Third_Task;
task body Third_Task
is
Ticket : Ticket_Type;
begin
for Index in 1..5 loop
Put
(Ticket,
"This is Third_Task, passing number ",
Index);
end loop;
end Third_Task;
begin
null;
-- Nothing there, all is done in tasks.
-- The application terminates when the last
-- task terminates.
--
-- The tasks which will be started by the environment
-- task are : Output_Server.Instance, First_Task,
-- Second_Task and Third_Task.
end Test;
next prev parent reply other threads:[~2010-02-05 20:56 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-02-05 20:54 Private or public task ? Hibou57 (Yannick Duchêne)
2010-02-05 20:56 ` Hibou57 (Yannick Duchêne) [this message]
2010-02-05 21:38 ` Jeffrey R. Carter
2010-02-05 21:53 ` Hibou57 (Yannick Duchêne)
2010-02-08 9:55 ` Alex R. Mosteo
2010-02-08 10:02 ` Jean-Pierre Rosen
2010-02-08 17:28 ` Maciej Sobczak
2010-02-09 8:43 ` Dmitry A. Kazakov
2010-02-09 12:07 ` Hibou57 (Yannick Duchêne)
2010-02-09 14:26 ` Jean-Pierre Rosen
2010-02-09 18:17 ` Hibou57 (Yannick Duchêne)
2010-02-10 8:17 ` Maciej Sobczak
2010-02-10 8:29 ` Hibou57 (Yannick Duchêne)
2010-02-10 8:40 ` Martin
2010-02-10 11:44 ` Jean-Pierre Rosen
2010-02-10 12:51 ` Martin
2010-02-10 16:17 ` Robert A Duff
2010-02-10 11:38 ` Jean-Pierre Rosen
2010-02-13 11:09 ` Dmitry A. Kazakov
2010-02-09 15:20 ` Robert A Duff
2010-02-09 18:26 ` Hibou57 (Yannick Duchêne)
2010-02-09 14:44 ` Alex R. Mosteo
2010-02-09 23:38 ` mkasun
2010-02-09 23:51 ` Robert A Duff
2010-02-10 0:01 ` Jeffrey R. Carter
2010-02-05 21:40 ` Dmitry A. Kazakov
2010-02-05 22:09 ` Hibou57 (Yannick Duchêne)
2010-02-05 22:57 ` sjw
2010-02-06 2:20 ` Hibou57 (Yannick Duchêne)
2010-02-06 2:23 ` Hibou57 (Yannick Duchêne)
2010-02-06 3:29 ` Jeffrey R. Carter
replies disabled
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox