From: Esa Riihonen <esa.riihonen.er@gmail.com>
Subject: Re: How to: communication between multiple tasks using protected objects - with no polling?
Date: Thu, 22 Jan 2015 05:32:42 -0800 (PST)
Date: 2015-01-22T05:32:42-08:00 [thread overview]
Message-ID: <537cf2a9-e18d-4efb-adb5-fa1914f48e3a@googlegroups.com> (raw)
In-Reply-To: <m9orn5$2pd$1@dont-email.me>
keskiviikko 21. tammikuuta 2015 20.39.07 UTC+2 Jeffrey Carter kirjoitti:
> On 01/21/2015 10:16 AM, Esa Riihonen wrote:
> > keskiviikko 21. tammikuuta 2015 2.47.29 UTC+2 Jeffrey Carter kirjoitti:
> >
> >> select
> >> PO1.Get (...);
> >> then abort
> >> PO2.Get (...);
> >> end select;
> >>
> >> This might, however, result in both entries being executed.
> >
> > If I understand correctly this will indeed work when selecting between two PO entries. And it wouldn't matter if both got executed (although I just now can't see how this could happen).
>
> Why both might be executed is kind of complicated. There was a thread on here
> about this some time ago. Consider the Ada-83 timed entry call:
>
> select
> T.E;
> or
> delay 1.0;
> end select;
>
> Ada 83 did not have protected types/objects or requeue, so if T.E was accepted
> before the delay expired, the delay could be cancelled. If the delay expired
> before the entry call was accepted then the entry call was aborted.
>
> Ada 95 introduced protected types/objects and requeue. This changed the
> semantics somewhat. Since the entry call (which can now be to a task or PO
> entry) can be requeued "with abort", the delay can't be canceled when the entry
> call is accepted, since a requeued with abort call can be aborted when the delay
> expires. Instead, we have to wait until the entry call completes before we can
> cancel the delay. If the delay expires while the entry call is being executed,
> that's OK because the execution of an entry call is abort deferred.
>
> Similar considerations apply to the ATC with both branches being entry calls and
> result in the possibility of both calls being executed.
>
OK, I think I understand it now. It seems that even Ada is not totally free of its intricasies that can provide some surprises for an uninitiated ;)
> > However, there seems not to be a natural way to expand this for more than
> > those two. This seems to be syntactically correct (compiles):
> >
> > select
> > PO1.Get (...);
> > then abort
> > select
> > PO2.Get (...);
> > then abort
> > PO3.Get (...);
> > end select
> > end select;
>
> Yes, these can be nested as far as desired.
>
> > But I'm not sure whether it would actually do what I want it to do. That is: suspend there until any of the entry barriers becomes true and then exit the whole outermost select statement?
>
> Yes, but it might execute any number of the entry calls.
>
> > Even if it works I have a (minor) concern that it is not 'pretty' as it doesn't reflect the mutual equality of the entries - and thus has a feel of 'hack' there ;)
>
> It's not pretty and it's not a good idea. ATC is said to be a very complex and
> heavyweight construct. I would only use it as a last resort.
>
> >> type Q_ID is (Q1, Q2, ...);
> >>
> >> type Q_Item (Q : Q_ID := Q_ID'First) is record
> >> case Q is
> >> when Q1 =>
> >> Item_1 : Q1_Item;
> >> when Q2 =>
> >> Item_2 : Q2:Item;
> >> ...
> >> end case;
> >> end record;
> >>
> >> protected Qs is
> >> entry Get (Item : out Q_Item);
> >> private -- Qs
> >> Q_1 : Q1_Q;
> >> Q_2 : Q2_Q;
> >> ...
> >> end Qs;
> >>
> >> protected body Qs is
> >> entry Get (Item : out Q_Item) when
> >> not Q_1.Is_Empty or not Q_2.Is_Empty or ...
> >> is
> >> -- Empty declarative part
> >> begin -- Get
> >> if not Q_1.Is_Empty then
> >> Item := (Q => Q1, Item_1 => Q_1.Get);
> >> elsif not Q_2.Is_Empty then
> >> item := (Q => Q2, Item_2 => Q_2.Get;
> >> ...
> >> end if;
> >> end Get;
> >> end Qs;
>
> I guess I was asleep when I wrote that. For one thing I left out a way to get
> things on the Qs. A better approach would be
>
> protected Queue is
> procedure Put (Item : in Q_Item);
> entry Get (Item : out Q_Item);
> private -- Queue
> Q : Q_Item_Q;
> end Queue;
>
> protected body Queue is
> procedure Put (Item : in Q_Item) is
> -- Empty declarative part
> begin -- Put
> Q.Put (Item => Item);
> end Put;
>
> entry Get (Item : out Q_Item) when not Q.Is_Empty is
> -- Empty declarative part
> begin -- Get
> Q.Get (Item => Item);
> end Get;
> end Queue;
At least that is more on my level of understanding - thanks.
> If you're willing to restrict yourself to a single compiler vendor, Ada 12 has
> synchronized queues as part of the standard library, and you could use one of
> those instead of writing your own. For earlier versions of Ada, which are
> supported by multiple compiler vendors, you could use PragmARC.Queue_Unbounded
> (or Queue_Bounded) from the PragmAda Reusable Components rather than writing
> your own. I guess it depends on whether writing your own PO is important for
> your learning experience.
Actually I think I at least would have to consider the synch queues in another part of my rehearsal program.
Many thanks for all the help provided.
> --
> Jeff Carter
> "Run away! Run away!"
> Monty Python and the Holy Grail
> 58
next prev parent reply other threads:[~2015-01-22 13:32 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-01-20 22:36 How to: communication between multiple tasks using protected objects - with no polling? Esa Riihonen
2015-01-21 0:19 ` Hubert
2015-01-21 16:53 ` Esa Riihonen
2015-01-21 23:22 ` Hubert
2015-01-22 13:24 ` Esa Riihonen
2015-01-21 0:47 ` Jeffrey Carter
2015-01-21 8:11 ` Simon Wright
2015-01-21 17:16 ` Esa Riihonen
2015-01-21 18:39 ` Jeffrey Carter
2015-01-22 13:32 ` Esa Riihonen [this message]
2015-01-21 8:28 ` Dmitry A. Kazakov
2015-01-21 17:34 ` Esa Riihonen
2015-01-21 18:56 ` Jacob Sparre Andersen
2015-01-21 20:15 ` Dmitry A. Kazakov
2015-01-22 21:52 ` G.B.
2015-01-23 8:25 ` Dmitry A. Kazakov
2015-01-21 20:02 ` Dmitry A. Kazakov
2015-01-22 13:37 ` Esa Riihonen
replies disabled
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox