comp.lang.ada
 help / color / mirror / Atom feed
From: "Vladimir Olensky" <vladimir_olensky@yahoo.com>
Subject: Re: Ada Protected Object Tutorial #1
Date: 1999/12/17
Date: 1999-12-17T00:00:00+00:00	[thread overview]
Message-ID: <s5kdne9qrs114@corp.supernews.com> (raw)
In-Reply-To: wcc1z8m8k9o.fsf@world.std.com


Robert A Duff wrote in message ...
>kaz@ashi.footprints.net (Kaz Kylheku) writes:


>> What if you want to block for something in the middle of the critical
region?
>> I assume that you can call a protected entry from within a protected
procedure.
>
>No, you can't.  If you want to block in the middle, then you have to
>call the thing an "entry" and not a "procedure".  One common thing to do
>is to have an entry with a True barrier, so it always goes right ahead,
>but then it can block by requeuing to a different entry (of the same
>protected object, or a different one); it will then block on a new
>barrier.  Protected procedures, on the other had, can't block.



Below is example with full explanation ( from Ada Rational ) which
is an excellent illustration to that.
Hope it will be helpful.

Regards,
Vladimir Olensky

=======================================
Ada Rational is available at:
http://www.adahome.com/LRM/95/Rationale/rat95html/rat95-contents.html
=====================================
Our final example introduces the ability to
requeue a call on another entry.

It sometimes happens that a service needs to be
provided in two parts and that the calling task has
to be suspended after the first part until
conditions are such that the second part can be
done. Two entry calls are then necessary but
attempts to program this in Ada 83 usually run into
difficulties; race conditions can arise in the
interval between the calls and there is often
unnecessary visibility of the internal protocol.


The example is of a broadcast signal. Tasks wait for
some event and then when it occurs all the waiting
tasks are released and the event reset. The
difficulty is to prevent tasks that call the wait
operation after the event has occurred, but before
the signal can be reset, from getting through. In
other words, we must reset the signal in preference
to letting new tasks through. The requeue statement
allows us to program such preference control. An
implementation is


   protected Event is
      entry Wait;
      entry Signal;
   private
      entry Reset;
      Occurred: Boolean := False;
   end Event;

   protected body Event is

      entry Wait when Occurred is
      begin
         null;        -- note null body
      end Wait;

      entry Signal when True is
      -- barrier is always true
      begin
         if Wait'Count > 0 then
            Occurred := True;
            requeue Reset;
         end if;
      end Signal;

      entry Reset when Wait'Count = 0 is
      begin
         Occurred := False;
      end Reset;

   end Event;

Tasks indicate that they wish to wait for the event
by the call

   Event.Wait;

and the happening of the event is notified by some
task calling

   Event.Signal;

whereupon all the waiting tasks are allowed to
proceed and the event is reset so that future calls
of Wait work properly.


The Boolean variable Occurred is normally false and
is only true while tasks are being released. The
entry Wait has no body but just exists so that
calling tasks can suspend themselves on its queue
while waiting for Occurred to become true.


The entry Signal is interesting. It has a
permanently true barrier and so is always processed.
If there are no tasks on the queue of Wait (that is
no tasks are waiting), then there is nothing to do
and so it exits. On the other hand if there are
tasks waiting then it must release them in such a
way that no further tasks can get on the queue but
then regain control so that it can reset the flag.
It does this by requeuing itself on the entry Reset
after setting Occurred to true to indicate that the
event has occurred.


The semantics of requeue are such that this
completes the action of Signal. However, remember
that at the end of the body of a protected entry or
procedure the barriers are reevaluated for those
entries which have tasks queued. In this case there
are indeed tasks on the queue for Wait and there is
also a task on the queue for Reset (the task that
called Signal in the first place); the barrier for
Wait is now true but of course the barrier for Reset
is false since there are still tasks on the queue
for Wait. A waiting task is thus allowed to execute
the body of Wait (being null this does nothing) and
the task thus proceeds and then the barrier
evaluation repeats. The same process continues until
all the waiting tasks have gone when finally the
barrier of Reset also becomes true. The original
task which called signal now executes the body of
Reset thus resetting Occurred to false so that the
system is once more in its initial state. The
protected object as a whole is now finally left
since there are no waiting tasks on any of the
barriers.


Note carefully that if any tasks had tried to call
Wait or Signal while the whole process was in
progress then they would not have been able to do so
because the protected object as a whole was busy.
This illustrates the two levels of protection and is
the underlying reason why a race condition does not
arise.

Another consequence of the two levels is that it
still all works properly even in the face of such
difficulties as timed and conditional calls and
aborts. The reader may recall, for example, that by
contrast, the Count attribute for entries in tasks
cannot be relied upon in the face of timed entry
calls.


A minor point to note is that the entry Reset is
declared in the private part of the protected type
and thus cannot be called from outside. Ada 95 also
allows a task to have a private part containing
private entries.


The above example has been used for illustration
only. The astute reader will have observed that the
condition is not strictly needed inside Signal;
without it the caller will simply always requeue and
then immediately be processed if there are no
waiting tasks. But the condition clarifies the
description. Indeed, the very astute reader might
care to note that we can actually program this
example in Ada 95 without using requeue at all. A
more realistic classic example is the disk scheduler
where a caller is requeued if the head is currently
over the wrong track.

In this section we have outlined the main features
of protected types. There are a number of detailed
aspects that we have not covered. The general
intent, however, should be clear. Protected types
provide a data-oriented approach to synchronization
which couples the high-level conditions (the
barriers) with the efficiency of monitors.
Furthermore the requeue statement provides a means
of programming preference control and thus enables
race conditions to be avoided.

It must be remembered, of course, that the existing
task model remains; the rendezvous will continue to
be a necessary approach in many circumstances of a
general nature (such as for directly passing
messages). But the protected object provides a
better paradigm for most data-oriented situations.







  reply	other threads:[~1999-12-17  0:00 UTC|newest]

Thread overview: 45+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
1999-12-15  0:00 Ada Protected Object Tutorial #1 James S. Rogers
1999-12-16  0:00 ` Kaz Kylheku
1999-12-16  0:00   ` John English
1999-12-16  0:00     ` Ed Falis
1999-12-16  0:00       ` Usenet Poster Boy
1999-12-17  0:00     ` Karel Th�nissen
1999-12-17  0:00       ` Laurent Guerby
1999-12-18  0:00         ` Kaz Kylheku
1999-12-18  0:00           ` Robert A Duff
1999-12-18  0:00             ` Kaz Kylheku
1999-12-18  0:00           ` Laurent Guerby
1999-12-18  0:00             ` Kaz Kylheku
1999-12-19  0:00               ` Laurent Guerby
1999-12-20  0:00                 ` Stanley R. Allen
1999-12-21  0:00               ` Robert I. Eachus
     [not found]             ` <33qr5scnbs04v391ev4541p5bv48hklg3q@4ax.com>
1999-12-20  0:00               ` Robert A Duff
1999-12-18  0:00         ` Karel Th�nissen
1999-12-18  0:00           ` Laurent Guerby
1999-12-17  0:00       ` Mike Silva
1999-12-24  0:00       ` Kenneth Almquist
1999-12-16  0:00   ` James S. Rogers
1999-12-17  0:00     ` Laurent Guerby
1999-12-17  0:00   ` Robert A Duff
1999-12-17  0:00     ` Vladimir Olensky [this message]
1999-12-17  0:00   ` Tucker Taft
1999-12-18  0:00     ` Kaz Kylheku
1999-12-18  0:00       ` Robert A Duff
1999-12-18  0:00         ` Kaz Kylheku
1999-12-19  0:00           ` swhalen
1999-12-19  0:00             ` Kaz Kylheku
1999-12-19  0:00               ` Robert Dewar
1999-12-19  0:00               ` Laurent Guerby
1999-12-20  0:00       ` Vladimir Olensky
1999-12-26  0:00         ` Ehud Lamm
1999-12-26  0:00           ` Robert Dewar
1999-12-26  0:00             ` Kaz Kylheku
1999-12-27  0:00               ` Robert Dewar
1999-12-27  0:00                 ` Jean-Pierre Rosen
1999-12-27  0:00                 ` Richard D Riehle
1999-12-27  0:00                   ` Robert Dewar
1999-12-31  0:00                     ` Richard D Riehle
1999-12-27  0:00               ` Robert Dewar
2000-01-02  0:00             ` Tucker Taft
1999-12-17  0:00 ` Robert A Duff
1999-12-18  0:00   ` Kaz Kylheku
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox