From: Randy Brukardt on
Am 22.02.2010, 02:51 Uhr, schrieb Bj�rn Persson <bjorn(a)rombobj�rn.se>:

> I had intended to switch from Charles to Ada.Containers, but I changed my
> mind when I learned that Ada.Containers can't even be read by multiple
> tasks at once.

For the record, we've studied this several times and have always concluded
that hidden synchronization is dangerous. That is, synchronization should be
explicit. Beyond that, it is impossible to come up with a reasonable
definition of what should be locked -- it really depends on the use of the
containers.

In the case of the containers, task safety of iterators and similar features
is something that defies a reasonable definition. The problem gets worse if
you include features used together (such as using First and Next to create a
loop of some sort). We'd probably need to make the locks visible in order
for them to be useful.

It's easy to wrap container operations in a protected object, and that is
always allowed (such operations are not potentially blocking). That allows
tailoring the locking for the actual usage, and even hiding the actual
container to prevent abuse.

Randy.


From: Georg Bauhaus on
Randy Brukardt schrieb:
> Am 22.02.2010, 02:51 Uhr, schrieb Bj�rn Persson <bjorn(a)rombobj�rn.se>:
>
>> I had intended to switch from Charles to Ada.Containers, but I changed my
>> mind when I learned that Ada.Containers can't even be read by multiple
> > tasks at once.

> It's easy to wrap container operations in a protected object, and that is
> always allowed (such operations are not potentially blocking). That allows
> tailoring the locking for the actual usage, and even hiding the actual
> container to prevent abuse.

Indeed, arent' there advantages in hiding data stores like
Ada.Containers behind some facade, whether the use is
sequential or not: everything else always smells of
exposed internal data structures, or lack of abstraction.
There need to be good reasons for using List, Set, etc.
as is, I think. Just like there should be good reasons
to expose arrays.
From: Stephen Leake on
"Randy Brukardt" <randy(a)rrsoftware.com> writes:

> Am 22.02.2010, 02:51 Uhr, schrieb Björn Persson <bjorn(a)rombobjörn.se>:
>
>> I had intended to switch from Charles to Ada.Containers, but I changed my
>> mind when I learned that Ada.Containers can't even be read by multiple
> > tasks at once.
>
> For the record, we've studied this several times and have always concluded
> that hidden synchronization is dangerous. That is, synchronization should be
> explicit. Beyond that, it is impossible to come up with a reasonable
> definition of what should be locked -- it really depends on the use of the
> containers.

I agree with this, but I think the OP was implying that you needed
locking even for read-only access of Ada.Containers from multiple
tasks; is that true? I don't see why it should be; each task declares
its own cursors, which don't interfere with each other.

Of course, there's nothing enforcing the read-only, so this is not
very safe.

--
-- Stephe
From: Alex R. Mosteo on
Stephen Leake wrote:

> "Randy Brukardt" <randy(a)rrsoftware.com> writes:
>
>> Am 22.02.2010, 02:51 Uhr, schrieb Björn Persson <bjorn(a)rombobjörn.se>:
>>
>>> I had intended to switch from Charles to Ada.Containers, but I changed
>>> my mind when I learned that Ada.Containers can't even be read by
>>> multiple
>> > tasks at once.
>>
>> For the record, we've studied this several times and have always
>> concluded that hidden synchronization is dangerous. That is,
>> synchronization should be explicit. Beyond that, it is impossible to come
>> up with a reasonable definition of what should be locked -- it really
>> depends on the use of the containers.
>
> I agree with this, but I think the OP was implying that you needed
> locking even for read-only access of Ada.Containers from multiple
> tasks; is that true? I don't see why it should be; each task declares
> its own cursors, which don't interfere with each other.

I think that the downward closure subprograms update some flags inside the
container. E.g., in gnat doubly linked lists, within the Query_Element:

procedure Query_Element
(Position : Cursor;
Process : not null access procedure (Element : Element_Type));

Pretty read-only, it seems, but inside you find:

declare
C : List renames Position.Container.all'Unrestricted_Access.all;
B : Natural renames C.Busy;
L : Natural renames C.Lock;

begin
B := B + 1;
L := L + 1;
(...)

So, basically, yes, even certain read-only uses are not thread-safe (Element
would be, at least in gnat implementation).

Never though of this before, but even wrapping a call to that in a protected
function would be dangerous, since protected functions are concurrent? And
that's a procedure with only "in" arguments, which would be callable from
such a function.

Am I right here?

From: sjw on
On Feb 25, 2:16 pm, "Alex R. Mosteo" <alejan...(a)mosteo.com> wrote:

> Never though of this before, but even wrapping a call to that in a protected
> function would be dangerous, since protected functions are concurrent? And
> that's a procedure with only "in" arguments, which would be callable from
> such a function.
>
> Am I right here?

I believe you are: LRM 9.5.1(1), "protected functions provide
concurrent read-only access to the data".

My normal mode of operation is to wrap the use of the Container (OK,
Booch Component!) in a package and use a lock to ensure single-
threaded access, with the Container outside any PO.