comp.lang.ada
 help / color / mirror / Atom feed
* new_line in a put_line
@ 2002-12-02  5:36 Vlad
  2002-12-02  9:47 ` Preben Randhol
                   ` (3 more replies)
  0 siblings, 4 replies; 30+ messages in thread
From: Vlad @ 2002-12-02  5:36 UTC (permalink / raw)


Hi all,

Is there a way of prepending a new_line to a put_line.
The reason I need this is that I have multiple tasks outputing to a\
single file. Some of them use Text_IO.Put rather then Text_IO.Put_Line.
And because of this, some of these outputs get written on the same line
as my outputs.

TIA

--
Vladimir Bednikov






^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: new_line in a put_line
  2002-12-02  5:36 Vlad
@ 2002-12-02  9:47 ` Preben Randhol
  2002-12-02 17:04   ` Frank J. Lhota
  2002-12-02 10:14 ` Dmitry A. Kazakov
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 30+ messages in thread
From: Preben Randhol @ 2002-12-02  9:47 UTC (permalink / raw)


Vlad wrote:
> Hi all,
> 
> Is there a way of prepending a new_line to a put_line.  The reason I
> need this is that I have multiple tasks outputing to a\ single file.
> Some of them use Text_IO.Put rather then Text_IO.Put_Line.  And
> because of this, some of these outputs get written on the same line as
> my outputs.

Either use ASCII.LF

Like

Put ("Hello Word" & ASCII.LF & "Anybody out there?" & ASCII.LF);

or

Put ("Hello Word");
New_Line;
Put ("Anybody out there?");

-- 
Preben Randhol ------------------------ http://www.pvv.org/~randhol/ --
                          �1984 is soon coming to a computer near you.�



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: new_line in a put_line
  2002-12-02  5:36 Vlad
  2002-12-02  9:47 ` Preben Randhol
@ 2002-12-02 10:14 ` Dmitry A. Kazakov
  2002-12-02 14:57 ` Matthew Heaney
  2002-12-02 15:49 ` Robert A Duff
  3 siblings, 0 replies; 30+ messages in thread
From: Dmitry A. Kazakov @ 2002-12-02 10:14 UTC (permalink / raw)


On Mon, 2 Dec 2002 16:06:58 +1030, "Vlad" <vbednikov@optusnet.com.au>
wrote:

>Is there a way of prepending a new_line to a put_line.
>The reason I need this is that I have multiple tasks outputing to a\
>single file. Some of them use Text_IO.Put rather then Text_IO.Put_Line.
>And because of this, some of these outputs get written on the same line
>as my outputs.

Concurrent access to Text_IO might be non-portable [bounded error?].
There are two better possibilities to do it:

1. Use a protected object (to implement mutex, but no I/O from
protected operations!)

2. Use a task that does all I/O (i.e. a monitor)

---
Regards,
Dmitry Kazakov
www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: new_line in a put_line
  2002-12-02  5:36 Vlad
  2002-12-02  9:47 ` Preben Randhol
  2002-12-02 10:14 ` Dmitry A. Kazakov
@ 2002-12-02 14:57 ` Matthew Heaney
  2002-12-03 11:33   ` Fraser Wilson
  2002-12-02 15:49 ` Robert A Duff
  3 siblings, 1 reply; 30+ messages in thread
From: Matthew Heaney @ 2002-12-02 14:57 UTC (permalink / raw)


"Vlad" <vbednikov@optusnet.com.au> wrote in message news:<aserlb$juh$1@fang.dsto.defence.gov.au>...
>
> Is there a way of prepending a new_line to a put_line.
> The reason I need this is that I have multiple tasks outputing to a\
> single file. Some of them use Text_IO.Put rather then Text_IO.Put_Line.
> And because of this, some of these outputs get written on the same line
> as my outputs.

If you have multiple tasks writing to the same file, then you're going
to have to synchronize access to the file through some intermediary,
as a task or protected object (the latter requires care).  Therefore,
there should already be a layer between Text_IO and the writing tasks,
which means that you can insert whatever extra code (e.g. a call to
New_Line) you deem necessary.



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: new_line in a put_line
  2002-12-02  5:36 Vlad
                   ` (2 preceding siblings ...)
  2002-12-02 14:57 ` Matthew Heaney
@ 2002-12-02 15:49 ` Robert A Duff
  3 siblings, 0 replies; 30+ messages in thread
From: Robert A Duff @ 2002-12-02 15:49 UTC (permalink / raw)


"Vlad" <vbednikov@optusnet.com.au> writes:

> Is there a way of prepending a new_line to a put_line.
> The reason I need this is that I have multiple tasks outputing to a\
> single file. Some of them use Text_IO.Put rather then Text_IO.Put_Line.
> And because of this, some of these outputs get written on the same line
> as my outputs.

You seem to be assuming that each call to Put or Put_Line is atomic.
That's not true, so inserting a new-line into the string passed to
Put_Line is not a correct solution.

If one task says:

    Put_Line("Hello");

and another task simultaneously says:

    Put_Line("Goodbye");

the program is erroneous, which means it can have totally unpredictable
behavior.  It might intersperse the characters, so you get:

    HelGoodl
    obye

or it might print what you want:

    Hello
    Goodbye

or it might crash, or anything else.

What you need to do is synchronize your accesses to the standard output
file, perhaps using a protected object.

- Bob



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: new_line in a put_line
  2002-12-02  9:47 ` Preben Randhol
@ 2002-12-02 17:04   ` Frank J. Lhota
  2002-12-05 11:10     ` Preben Randhol
  0 siblings, 1 reply; 30+ messages in thread
From: Frank J. Lhota @ 2002-12-02 17:04 UTC (permalink / raw)


"Preben Randhol" <randhol+news@pvv.org> wrote in message
news:slrnaumb0a.en.randhol+news@kiuk0152.chembio.ntnu.no...
> Vlad wrote:
> Either use ASCII.LF
>
> Like
>
> Put ("Hello Word" & ASCII.LF & "Anybody out there?" & ASCII.LF);
>
> or <snip>

There is no one llne terminator used by all operating systems. The Microsoft
OS's use the character sequence (ASCII.CR, ASCII.LF) to end a line. The Mac
OS uses ASCII.CR. And VMS uses an entirely different way of indicating the
end of a text line (basically, each line has a prefix indicating the number
of characters in the line). For this reason, there is no guarantee that
writing ASCII.LF will create a new line on all platforms. The right way to
get a new line is to call New_Line.

Of course, this does not in and of itself solve the poster's original
problem, but as indicated elsewhere in this thread, the right solution is to
use a separate task or protected object for writing to the file.






^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: new_line in a put_line
  2002-12-02 14:57 ` Matthew Heaney
@ 2002-12-03 11:33   ` Fraser Wilson
  2002-12-03 15:01     ` Dmitry A. Kazakov
  0 siblings, 1 reply; 30+ messages in thread
From: Fraser Wilson @ 2002-12-03 11:33 UTC (permalink / raw)


mheaney@on2.com (Matthew Heaney) writes:

> If you have multiple tasks writing to the same file, then you're going
> to have to synchronize access to the file through some intermediary,
> as a task or protected object (the latter requires care).

I've seen a couple of mentions of problems using protected objects for
atomic file output.  What's the specific issue?  I.e., why isn't this
sufficient?

   protected File_Operation is
      procedure Put_Line (Text : String);
   end File_Operation;

   protected body File_Operation is
      procedure Put_Line (Text : String) is
      begin
         Ada.Text_IO.Put_Line (Text);
      end Put_Line;
   end File_Operation;

Oh, wait on, is it something to do with 9.5.1(8)?

Fraser.



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: new_line in a put_line
@ 2002-12-03 11:52 Grein, Christoph
  2002-12-04  9:39 ` Fraser Wilson
  0 siblings, 1 reply; 30+ messages in thread
From: Grein, Christoph @ 2002-12-03 11:52 UTC (permalink / raw)


> I've seen a couple of mentions of problems using protected objects for
> atomic file output.  What's the specific issue?  I.e., why isn't this
> sufficient?
> 
>    protected File_Operation is
>       procedure Put_Line (Text : String);
>    end File_Operation;
> 
>    protected body File_Operation is
>       procedure Put_Line (Text : String) is
>       begin
>          Ada.Text_IO.Put_Line (Text);
>       end Put_Line;
>    end File_Operation;
> 
> Oh, wait on, is it something to do with 9.5.1(8)?

You've spotted it. Also 9.5.1(18).

> Fraser.



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: new_line in a put_line
  2002-12-03 11:33   ` Fraser Wilson
@ 2002-12-03 15:01     ` Dmitry A. Kazakov
  2002-12-04  9:31       ` Fraser Wilson
  0 siblings, 1 reply; 30+ messages in thread
From: Dmitry A. Kazakov @ 2002-12-03 15:01 UTC (permalink / raw)


On 03 Dec 2002 12:33:37 +0100, Fraser Wilson
<newsfraser@blancolioni.org> wrote:

>mheaney@on2.com (Matthew Heaney) writes:
>
>> If you have multiple tasks writing to the same file, then you're going
>> to have to synchronize access to the file through some intermediary,
>> as a task or protected object (the latter requires care).
>
>I've seen a couple of mentions of problems using protected objects for
>atomic file output.  What's the specific issue?  I.e., why isn't this
>sufficient?

Just do not do I/O from them. Define a mutex as a protected object and
a spin lock as a controlled type (less troubles with releasing a
mutex):

with Ada.Finalization;
package Sync is
   protected type Mutex is
      entry Seize;
      procedure Release;
   private
      Owned : Boolean := False;
   end Mutex;
   type Lock (Resource : access Mutex) is new
      Ada.Finalization.Limited_Controlled with private;      
private
   type Lock (Resource : access Mutex) is new
      Ada.Finalization.Limited_Controlled with null record;
   procedure Initialize (Object : in out Lock);
   procedure Finalize (Object : in out Lock);
end Sync;
---------------------------------------
package body Sync is
   protected body Mutex is   
      entry Seize when not Owned is
      begin
         Owned := True;
      end Seize;
      procedure Release is
      begin
         Owned := False;
      end Release; 
   end Mutex;
   procedure Initialize (Object : in out Lock) is
   begin
      Object.Resource.Seize;
   end Initialize;
   procedure Finalize (Object : in out Lock) is
   begin
      Object.Resource.Release;
   end Finalize;
end Sync;
---------------------------------------
Now your task-safe I/O package could be very sraightforward:

package File_Operation is
   procedure Put_Line (Text : String);
end File_Operation;
--------------------------------------------------------
with Ada.Text_IO;
with Sync; use Sync;
package body File_Operation is
   Write_Mutex : aliased Mutex;
   procedure Put_Line (Text : String) is
      Get_It : Lock (Write_Mutex'Access);
   begin
      Ada.Text_IO.Put_Line (Text);
   end Put_Line;
end File_Operation;

>Oh, wait on, is it something to do with 9.5.1(8)?

There could be an implementation of protected objects that would use
one lock for all of them. Now imagine, that you do I/O from a
protected operation, so no other protected operation can start on any
other object until I/O completion. That would be sort of MS Windows!
(:-))

---
Regards,
Dmitry Kazakov
www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: new_line in a put_line
  2002-12-03 15:01     ` Dmitry A. Kazakov
@ 2002-12-04  9:31       ` Fraser Wilson
  2002-12-04 14:10         ` Dmitry A. Kazakov
  0 siblings, 1 reply; 30+ messages in thread
From: Fraser Wilson @ 2002-12-04  9:31 UTC (permalink / raw)


Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> writes:

> Just do not do I/O from them. Define a mutex as a protected object and
> a spin lock as a controlled type (less troubles with releasing a
> mutex):

[..]

>    procedure Put_Line (Text : String) is
>       Get_It : Lock (Write_Mutex'Access);
>    begin
>       Ada.Text_IO.Put_Line (Text);
>    end Put_Line;

Something inside me rebels at using side-effects from a declaration
like that.  I can't really talk; my database library unlocks objects
as they go out of scope, but ... well, I know that code gets executed
in declarations, but I don't necessarily want to be this aware of it.

On the other hand, it's just a monitor, I shouldn't be so scared :)

cheers,
Fraser.






^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: new_line in a put_line
  2002-12-03 11:52 Grein, Christoph
@ 2002-12-04  9:39 ` Fraser Wilson
  0 siblings, 0 replies; 30+ messages in thread
From: Fraser Wilson @ 2002-12-04  9:39 UTC (permalink / raw)


"Grein, Christoph" <christoph.grein@eurocopter.com> writes:

> You've spotted it. Also 9.5.1(18).

That'll teach me to scan too quickly.  Thanks!

For those of you without the RM handy, performing potentially blocking
actions is a bounded error, and I/O is potentially blocking (duh!)

Fraser.



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: new_line in a put_line
@ 2002-12-04 10:03 Grein, Christoph
  0 siblings, 0 replies; 30+ messages in thread
From: Grein, Christoph @ 2002-12-04 10:03 UTC (permalink / raw)


> >    procedure Put_Line (Text : String) is
> >       Get_It : Lock (Write_Mutex'Access);
> >    begin
> >       Ada.Text_IO.Put_Line (Text);
> >    end Put_Line;
> 
> Something inside me rebels at using side-effects from a declaration
> like that.  I can't really talk; my database library unlocks objects
> as they go out of scope, but ... well, I know that code gets executed
> in declarations, but I don't necessarily want to be this aware of it.
> 
> On the other hand, it's just a monitor, I shouldn't be so scared :)

This is exactly the kind of use limited controlled types are destined for.
There is a paragraph in the AARM stating that such a (seemingly unused) object 
(Get_It) must not be optimized away.

For unlimited controlled types, this does not hold, i.e. they may be optimized 
away.



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: new_line in a put_line
  2002-12-04  9:31       ` Fraser Wilson
@ 2002-12-04 14:10         ` Dmitry A. Kazakov
  2002-12-04 15:23           ` Robert A Duff
  2002-12-04 15:25           ` Stephen Leake
  0 siblings, 2 replies; 30+ messages in thread
From: Dmitry A. Kazakov @ 2002-12-04 14:10 UTC (permalink / raw)


On 04 Dec 2002 10:31:15 +0100, Fraser Wilson
<newsfraser@blancolioni.org> wrote:

>Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> writes:
>
>> Just do not do I/O from them. Define a mutex as a protected object and
>> a spin lock as a controlled type (less troubles with releasing a
>> mutex):
>
>[..]
>
>>    procedure Put_Line (Text : String) is
>>       Get_It : Lock (Write_Mutex'Access);
>>    begin
>>       Ada.Text_IO.Put_Line (Text);
>>    end Put_Line;
>
>Something inside me rebels at using side-effects from a declaration
>like that. 

Right, right. It is also my opinion [there was a thread regarding this
subject in c.l.a] that using unused (:-)) objects probably indicates a
design problem. A task-based design might be better.

> I can't really talk; my database library unlocks objects
>as they go out of scope, but ... well, I know that code gets executed
>in declarations, but I don't necessarily want to be this aware of it.
>
>On the other hand, it's just a monitor, I shouldn't be so scared :)

You might also pack seizing the mutex into a "proxy" object
(File_Channel):

   type File_Channel is limited private;
   procedure Put (File : in out File_Channel; Text : String);
   procedure Put_Line (File : in out File_Channel; Text : String);
   procedure New_Line (File : in out File_Channel; Text : String);
...
private
   type File_Channel is
      new Ada.Finalization.Limited_Controlled with null record;
   procedure Initialize (File : in out File_Channel);
   procedure Finalize (File : in out File_Channel);

Initialize would seize the mutex, Finalize would release it. Thus only
one instance of File_Channel may exist at a time.

---
Regards,
Dmitry Kazakov
www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: new_line in a put_line
  2002-12-04 14:10         ` Dmitry A. Kazakov
@ 2002-12-04 15:23           ` Robert A Duff
  2002-12-04 16:15             ` Dmitry A. Kazakov
  2002-12-04 15:25           ` Stephen Leake
  1 sibling, 1 reply; 30+ messages in thread
From: Robert A Duff @ 2002-12-04 15:23 UTC (permalink / raw)


Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> writes:

> On 04 Dec 2002 10:31:15 +0100, Fraser Wilson
> <newsfraser@blancolioni.org> wrote:
> 
> >Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> writes:
> >
> >> Just do not do I/O from them. Define a mutex as a protected object and
> >> a spin lock as a controlled type (less troubles with releasing a
> >> mutex):
> >
> >[..]
> >
> >>    procedure Put_Line (Text : String) is
> >>       Get_It : Lock (Write_Mutex'Access);
> >>    begin
> >>       Ada.Text_IO.Put_Line (Text);
> >>    end Put_Line;
> >
> >Something inside me rebels at using side-effects from a declaration
> >like that. 
> 
> Right, right. It is also my opinion [there was a thread regarding this
> subject in c.l.a] that using unused (:-)) objects probably indicates a
> design problem. A task-based design might be better.

There is nothing wrong with declaring a limited controlled object that
is used only for its Initialize/Finalize effects.  It's a common idiom
in Ada (and also in C++).

It's the *only* way in Ada to safely ensure that resources get cleaned
up -- so telling people not to use it is bad advice, IMHO.

You could reasonably argue that Ada ought to have a better syntax for
this -- one that does not involve creating dummy types.  In fact, such a
syntax was proposed as part of Ada 9X, but was rejected on the grounds
that limited controlled types provide all the necessary functionality.

A task-based design would work just fine, too.

- Bob



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: new_line in a put_line
  2002-12-04 14:10         ` Dmitry A. Kazakov
  2002-12-04 15:23           ` Robert A Duff
@ 2002-12-04 15:25           ` Stephen Leake
  2002-12-04 16:55             ` Jeffrey Carter
  1 sibling, 1 reply; 30+ messages in thread
From: Stephen Leake @ 2002-12-04 15:25 UTC (permalink / raw)


Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> writes:

> On 04 Dec 2002 10:31:15 +0100, Fraser Wilson
> <newsfraser@blancolioni.org> wrote:
> 
> >Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> writes:
> >
> >> Just do not do I/O from them. Define a mutex as a protected object and
> >> a spin lock as a controlled type (less troubles with releasing a
> >> mutex):
> >
> >[..]
> >
> >>    procedure Put_Line (Text : String) is
> >>       Get_It : Lock (Write_Mutex'Access);
> >>    begin
> >>       Ada.Text_IO.Put_Line (Text);
> >>    end Put_Line;
> >
> >Something inside me rebels at using side-effects from a declaration
> >like that. 
> 
> Right, right. It is also my opinion [there was a thread regarding this
> subject in c.l.a] that using unused (:-)) objects probably indicates a
> design problem. 

That's what pragma Unreferenced (in GNAT) is for; it documents that
the object is declared only for the hidden effects of Initialize and
Finalize.

Assuming Lock is a controlled type, that releases the lock in
Finalize, this is an excellent design.

-- 
-- Stephe



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: new_line in a put_line
  2002-12-04 15:23           ` Robert A Duff
@ 2002-12-04 16:15             ` Dmitry A. Kazakov
  2002-12-04 18:11               ` tmoran
  0 siblings, 1 reply; 30+ messages in thread
From: Dmitry A. Kazakov @ 2002-12-04 16:15 UTC (permalink / raw)


On Wed, 4 Dec 2002 15:23:14 GMT, Robert A Duff
<bobduff@shell01.TheWorld.com> wrote:

>Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> writes:
>
>> On 04 Dec 2002 10:31:15 +0100, Fraser Wilson
>> <newsfraser@blancolioni.org> wrote:
>> 
>> >Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> writes:
>> >
>> >> Just do not do I/O from them. Define a mutex as a protected object and
>> >> a spin lock as a controlled type (less troubles with releasing a
>> >> mutex):
>> >
>> >[..]
>> >
>> >>    procedure Put_Line (Text : String) is
>> >>       Get_It : Lock (Write_Mutex'Access);
>> >>    begin
>> >>       Ada.Text_IO.Put_Line (Text);
>> >>    end Put_Line;
>> >
>> >Something inside me rebels at using side-effects from a declaration
>> >like that. 
>> 
>> Right, right. It is also my opinion [there was a thread regarding this
>> subject in c.l.a] that using unused (:-)) objects probably indicates a
>> design problem. A task-based design might be better.
>
>There is nothing wrong with declaring a limited controlled object that
>is used only for its Initialize/Finalize effects.  It's a common idiom
>in Ada (and also in C++).

Right, it works and it is safe, but still to my taste it is a bad
design because of using exclusively side-effects.

>It's the *only* way in Ada to safely ensure that resources get cleaned
>up -- so telling people not to use it is bad advice, IMHO.

You mean controlled objects? Yes, I didn't argue against them. It is
only that I do not like "pure" lock-objects [like Lock above],
something tells me that there should be a better way. For instance, to
fuse lock with a proxy object as in my example.

>You could reasonably argue that Ada ought to have a better syntax for
>this -- one that does not involve creating dummy types.  In fact, such a
>syntax was proposed as part of Ada 9X, but was rejected on the grounds
>that limited controlled types provide all the necessary functionality.

No that was a right decision, because it would change nothing, it
would remain just a dressed side effect.

The problem as I see it, is of course that one tries to express a
CRITICAL SECTION in terms of OBJECTS. This *cannot* be good. The first
is about execution flow control the second is about data. Only OO
fundamentalists believe that objects is everything that one might
wish. (:-))

>A task-based design would work just fine, too.

---
Regards,
Dmitry Kazakov
www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: new_line in a put_line
  2002-12-04 15:25           ` Stephen Leake
@ 2002-12-04 16:55             ` Jeffrey Carter
  2002-12-04 17:24               ` Stephen Leake
  2002-12-04 17:43               ` Warren W. Gay VE3WWG
  0 siblings, 2 replies; 30+ messages in thread
From: Jeffrey Carter @ 2002-12-04 16:55 UTC (permalink / raw)


Stephen Leake wrote:
> 
> Assuming Lock is a controlled type, that releases the lock in
> Finalize, this [using a semaphore] is an excellent design.

I would disagree. Using a high-level feature such as a protected type to 
implement a low-level construct such as a semaphore is abstraction 
inversion. Ada has high-level concurrency features, and it should be 
possible to solve this problem directly in terms of those features. 
Using a semaphore probably indicates a lack of familiarity with those 
features rather than a reasoned decision that a semaphore is the best 
solution.

For a real-time system I designed a debug-output system based on a 
protected bounded queue of bounded strings with a very high ceiling 
priority (any task could make a debug-output call) and a task with a 
very low priority (it only ran when nothing else was running) to 
actually do the output. Some logic deleted the oldest message in the 
queue if new messages were added when the queue was full, though that 
never happened in practice. The idea was that calls to produce output 
never blocked the caller so the system had minimal impact on the timing 
of the system.

Of course, that had more complex requirements than what is being 
discussed here. Apparently the OP doesn't mind if the tasks are blocked 
during output, so simply rendezvousing with a task that does the output 
would solve the problem and be simpler and clearer than the semaphore + 
protected type approach.

-- 
Jeff Carter
"Go and boil your bottoms."
Monty Python & the Holy Grail




^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: new_line in a put_line
  2002-12-04 16:55             ` Jeffrey Carter
@ 2002-12-04 17:24               ` Stephen Leake
  2002-12-04 17:43               ` Warren W. Gay VE3WWG
  1 sibling, 0 replies; 30+ messages in thread
From: Stephen Leake @ 2002-12-04 17:24 UTC (permalink / raw)


Jeffrey Carter <jrcarter@acm.org> writes:

> Stephen Leake wrote:
> > Assuming Lock is a controlled type, that releases the lock in
> > Finalize, this [using a semaphore] is an excellent design.
> 
> I would disagree. Using a high-level feature such as a protected type
> to implement a low-level construct such as a semaphore is abstraction
> inversion. 

I said nothing about a "protected" type; I was talking about a
"controlled" type.

-- 
-- Stephe



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: new_line in a put_line
  2002-12-04 16:55             ` Jeffrey Carter
  2002-12-04 17:24               ` Stephen Leake
@ 2002-12-04 17:43               ` Warren W. Gay VE3WWG
  2002-12-05  1:31                 ` Jeffrey Carter
  1 sibling, 1 reply; 30+ messages in thread
From: Warren W. Gay VE3WWG @ 2002-12-04 17:43 UTC (permalink / raw)


Jeffrey Carter wrote:
> Stephen Leake wrote:
>> Assuming Lock is a controlled type, that releases the lock in
>> Finalize, this [using a semaphore] is an excellent design.
> 
...
> Of course, that had more complex requirements than what is being 
> discussed here. Apparently the OP doesn't mind if the tasks are blocked 
> during output, so simply rendezvousing with a task that does the output 
> would solve the problem and be simpler and clearer than the semaphore + 
> protected type approach.

The Rendezvous has the benefit that the request to perform output
is queued. This results in greater efficiency on most platforms
because it avoids having threads wake up and test to see if they
won out on the condition variable set (protected object).

It also guarantees "order". With the protected object approach a
"Johnnie come lately" task could gain access while already blocked
tasks are waiting to gain access -- destroying the waiting line
sequence. This may create some confusing to read "output".

However, the mutex does have one advantage in this scenario. If you
have to perform multiple calls to Text_IO then it makes more sense
to lock, perform I/O and then unlock. For example:

Lock;
New_Line;
Put_line("Hello World");
Unlock;

You could implement Lock and Unlock using the Rendevous however.
-- 
Warren W. Gay VE3WWG
http://home.cogeco.ca/~ve3wwg
Need to clean up your PATH or LD_LIBRARY_PATH? Try unique_path at
http://home.cogeco.ca/~ve3wwg/unique_path (awk script)




^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: new_line in a put_line
  2002-12-04 16:15             ` Dmitry A. Kazakov
@ 2002-12-04 18:11               ` tmoran
  2002-12-04 20:21                 ` Simon Wright
  2002-12-05  9:36                 ` Dmitry A. Kazakov
  0 siblings, 2 replies; 30+ messages in thread
From: tmoran @ 2002-12-04 18:11 UTC (permalink / raw)


> The problem as I see it, is of course that one tries to express a
> CRITICAL SECTION in terms of OBJECTS. This *cannot* be good. The first
> is about execution flow control the second is about data.
  Then you should use a task.  Using the lock object is a short, possibly
faster, idiom to accomplish the purpose.  It's like the "good morning" in
"Good morning gentlemen.  I have some bad news..."  You are not trying to
say the morning is a good one, you are trying to say "ok, let's get
started, I have the floor and want your attention." "Good morning" is
quicker.
  It may require some comments to explain what's going on to someone
unfamiliar with the idiom, but it's a valuable idiom.  A recent thread
here mentioned using an asm string scan operation in conjunction with
boolean arrays.  A purist might say that's not what it was intended for,
but a pragmatist would say it's an excellent idea.



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: new_line in a put_line
  2002-12-04 18:11               ` tmoran
@ 2002-12-04 20:21                 ` Simon Wright
  2002-12-05  9:36                 ` Dmitry A. Kazakov
  1 sibling, 0 replies; 30+ messages in thread
From: Simon Wright @ 2002-12-04 20:21 UTC (permalink / raw)


tmoran@acm.org writes:

> > The problem as I see it, is of course that one tries to express a
> > CRITICAL SECTION in terms of OBJECTS. This *cannot* be good. The first
> > is about execution flow control the second is about data.
>   Then you should use a task.  Using the lock object is a short, possibly
> faster, idiom to accomplish the purpose.  It's like the "good morning" in
> "Good morning gentlemen.  I have some bad news..."  You are not trying to
> say the morning is a good one, you are trying to say "ok, let's get
> started, I have the floor and want your attention." "Good morning" is
> quicker.
>   It may require some comments to explain what's going on to someone
> unfamiliar with the idiom, but it's a valuable idiom.  A recent thread
> here mentioned using an asm string scan operation in conjunction with
> boolean arrays.  A purist might say that's not what it was intended for,
> but a pragmatist would say it's an excellent idea.

I suppose the tension is between an open protocol, using lock objects,
with the risk that someone forgets to use it, and a closed protocol
which ensures that people do the right thing but requires interfaces
for all the things they need to do.



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: new_line in a put_line
  2002-12-04 17:43               ` Warren W. Gay VE3WWG
@ 2002-12-05  1:31                 ` Jeffrey Carter
  2002-12-05 18:11                   ` Warren W. Gay VE3WWG
  0 siblings, 1 reply; 30+ messages in thread
From: Jeffrey Carter @ 2002-12-05  1:31 UTC (permalink / raw)


Warren W. Gay VE3WWG wrote:
> 
> The Rendezvous has the benefit that the request to perform output
> is queued. This results in greater efficiency on most platforms
> because it avoids having threads wake up and test to see if they
> won out on the condition variable set (protected object).

I think you're mistaken. After performing a protected procedure or 
entry, it's perfectly legal for the same task to check the barriers of 
the object. I don't know about implementations, but this is certainly 
intended behavior for protected objects. Thus, tasks don't have to "wake 
up" until they are ready to run.

> 
> It also guarantees "order". With the protected object approach a
> "Johnnie come lately" task could gain access while already blocked
> tasks are waiting to gain access -- destroying the waiting line
> sequence. This may create some confusing to read "output".

If you need to guarantee order for a protected operation it should be an 
entry. This guarantees the same order as for a task entry.

-- 
Jeff Carter
"You've got the brain of a four-year-old boy,
and I bet he was glad to get rid of it."
Horse Feathers




^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: new_line in a put_line
@ 2002-12-05  6:16 Grein, Christoph
  2002-12-05  9:44 ` Dmitry A. Kazakov
  0 siblings, 1 reply; 30+ messages in thread
From: Grein, Christoph @ 2002-12-05  6:16 UTC (permalink / raw)


> You might also pack seizing the mutex into a "proxy" object
> (File_Channel):
> 
>    type File_Channel is limited private;
>    procedure Put (File : in out File_Channel; Text : String);
>    procedure Put_Line (File : in out File_Channel; Text : String);
>    procedure New_Line (File : in out File_Channel; Text : String);
> ...
> private
>    type File_Channel is
>       new Ada.Finalization.Limited_Controlled with null record;
>    procedure Initialize (File : in out File_Channel);
>    procedure Finalize (File : in out File_Channel);
> 
> Initialize would seize the mutex, Finalize would release it. Thus only
> one instance of File_Channel may exist at a time.

No, nothing prevents you from declaring lots of File_Channel objects concurrently, even 
arrays of them.



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: new_line in a put_line
@ 2002-12-05  6:28 Grein, Christoph
  2002-12-05 14:19 ` Stephen Leake
  0 siblings, 1 reply; 30+ messages in thread
From: Grein, Christoph @ 2002-12-05  6:28 UTC (permalink / raw)


> > >>    procedure Put_Line (Text : String) is
> > >>       Get_It : Lock (Write_Mutex'Access);
> > >>    begin
> > >>       Ada.Text_IO.Put_Line (Text);
> > >>    end Put_Line;
> > >
> > >Something inside me rebels at using side-effects from a declaration
> > >like that. 
> > 
> > Right, right. It is also my opinion [there was a thread regarding this
> > subject in c.l.a] that using unused (:-)) objects probably indicates a
> > design problem. 
> 
> That's what pragma Unreferenced (in GNAT) is for; it documents that
> the object is declared only for the hidden effects of Initialize and
> Finalize.
> 
> Assuming Lock is a controlled type, that releases the lock in
> Finalize, this is an excellent design.

This should only be necessary for objects of not limited controlled types. As I said, 
limited controlled objects must not be optimized away.



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: new_line in a put_line
  2002-12-04 18:11               ` tmoran
  2002-12-04 20:21                 ` Simon Wright
@ 2002-12-05  9:36                 ` Dmitry A. Kazakov
  2002-12-05 22:40                   ` tmoran
  1 sibling, 1 reply; 30+ messages in thread
From: Dmitry A. Kazakov @ 2002-12-05  9:36 UTC (permalink / raw)


On Wed, 04 Dec 2002 18:11:24 GMT, tmoran@acm.org wrote:

>> The problem as I see it, is of course that one tries to express a
>> CRITICAL SECTION in terms of OBJECTS. This *cannot* be good. The first
>> is about execution flow control the second is about data.
>  Then you should use a task.

Maybe, Ada.Streams + a hidden task or something like Jeffrey Carter
proposed.

The problem (maybe a mental one) is than one would say - what a
monster for such a simple thing! There can be two answers for that:

A. It is inherently complex
B. There should be a better solution [if we change the language]

Honestly, I do not know which answer is right.

---
Regards,
Dmitry Kazakov
www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: new_line in a put_line
  2002-12-05  6:16 Grein, Christoph
@ 2002-12-05  9:44 ` Dmitry A. Kazakov
  0 siblings, 0 replies; 30+ messages in thread
From: Dmitry A. Kazakov @ 2002-12-05  9:44 UTC (permalink / raw)


On Thu, 5 Dec 2002 07:16:10 +0100 (MET), "Grein, Christoph"
<christoph.grein@eurocopter.com> wrote:

>> You might also pack seizing the mutex into a "proxy" object
>> (File_Channel):
>> 
>>    type File_Channel is limited private;
>>    procedure Put (File : in out File_Channel; Text : String);
>>    procedure Put_Line (File : in out File_Channel; Text : String);
>>    procedure New_Line (File : in out File_Channel; Text : String);
>> ...
>> private
>>    type File_Channel is
>>       new Ada.Finalization.Limited_Controlled with null record;
>>    procedure Initialize (File : in out File_Channel);
>>    procedure Finalize (File : in out File_Channel);
>> 
>> Initialize would seize the mutex, Finalize would release it. Thus only
>> one instance of File_Channel may exist at a time.
>
>No, nothing prevents you from declaring lots of File_Channel objects concurrently, even 
>arrays of them.

OK, bad wording, I admit. Under "exists" I actually meant "exists at
run-time and is fully initialized".

---
Regards,
Dmitry Kazakov
www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: new_line in a put_line
  2002-12-02 17:04   ` Frank J. Lhota
@ 2002-12-05 11:10     ` Preben Randhol
  0 siblings, 0 replies; 30+ messages in thread
From: Preben Randhol @ 2002-12-05 11:10 UTC (permalink / raw)


Frank J. Lhota wrote:
> There is no one llne terminator used by all operating systems. The
> Microsoft OS's use the character sequence (ASCII.CR, ASCII.LF) to end
> a line. The Mac OS uses ASCII.CR. And VMS uses an entirely different
> way of indicating the end of a text line (basically, each line has a
> prefix indicating the number of characters in the line). For this
> reason, there is no guarantee that writing ASCII.LF will create a new
> line on all platforms. The right way to get a new line is to call
> New_Line.

It works in Linux, the rest is left for a task for the reader ;-) The
point is that if the OS is not specified I assume they use the same as I
do. :-)

> Of course, this does not in and of itself solve the poster's original
> problem, but as indicated elsewhere in this thread, the right solution
> is to use a separate task or protected object for writing to the file.

I misunderstood the original question. I assumed he used a protected
object.

-- 
Preben Randhol ------------------------ http://www.pvv.org/~randhol/ --
                          �1984 is soon coming to a computer near you.�



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: new_line in a put_line
  2002-12-05  6:28 new_line in a put_line Grein, Christoph
@ 2002-12-05 14:19 ` Stephen Leake
  0 siblings, 0 replies; 30+ messages in thread
From: Stephen Leake @ 2002-12-05 14:19 UTC (permalink / raw)


"Grein, Christoph" <christoph.grein@eurocopter.com> writes:

> > > >>    procedure Put_Line (Text : String) is
> > > >>       Get_It : Lock (Write_Mutex'Access);
> > > >>    begin
> > > >>       Ada.Text_IO.Put_Line (Text);
> > > >>    end Put_Line;
> > > >
> > > >Something inside me rebels at using side-effects from a declaration
> > > >like that. 
> > > 
> > > Right, right. It is also my opinion [there was a thread regarding this
> > > subject in c.l.a] that using unused (:-)) objects probably indicates a
> > > design problem. 
> > 
> > That's what pragma Unreferenced (in GNAT) is for; it documents that
> > the object is declared only for the hidden effects of Initialize and
> > Finalize.
> > 
> > Assuming Lock is a controlled type, that releases the lock in
> > Finalize, this is an excellent design.
> 
> This should only be necessary 

It's not "necessary" in any case. It does avoid a warning from GNAT,
and it informs the reader. That's what I meant by "documents".

> for objects of not limited controlled types. As I said, limited
> controlled objects must not be optimized away.

Yes, the reader could lookup the type of the variable and realized it
is limited controlled. Unreferenced is quicker and clearer.

-- 
-- Stephe



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: new_line in a put_line
  2002-12-05  1:31                 ` Jeffrey Carter
@ 2002-12-05 18:11                   ` Warren W. Gay VE3WWG
  0 siblings, 0 replies; 30+ messages in thread
From: Warren W. Gay VE3WWG @ 2002-12-05 18:11 UTC (permalink / raw)


Jeffrey Carter wrote:
> Warren W. Gay VE3WWG wrote:
> 
>> The Rendezvous has the benefit that the request to perform output
>> is queued. This results in greater efficiency on most platforms
>> because it avoids having threads wake up and test to see if they
>> won out on the condition variable set (protected object).
> 
> I think you're mistaken. After performing a protected procedure or 
> entry, it's perfectly legal for the same task to check the barriers of 
> the object. I don't know about implementations, but this is certainly 
> intended behavior for protected objects. Thus, tasks don't have to "wake 
> up" until they are ready to run.

When you look behind the scenes at the _implementation_, for some
platforms (for some UNIX at least), these things boil down to pthread
calls. For example:

   http://www.cs.nmsu.edu/~jcook/Tools/pthreads/pthread_cond.html says :

   int pthread_cond_signal (pthread_cond_t *cond);

   This wakes up at least one thread blocked on the condition variable.
   Remember that they must each re-acquire the mutex before they can
   return, so they will exit the block one at a time.

So if pthread_cond_signal() is used at all in the implementation of
a protected object, you will have (on many platforms) the possibility
that a number of threads awaken to see if they "won".  On some
UNIX platforms this is a serious issue when you have 500+ threads
(this is similar to the UNIX problem of 500+ processes waking up
when a semaphore gets notified -- believe it or not, on
many platforms, all processes unswap to see if they "won", leading
to serious performance problems [e.g. HPUX].)

Now whether this is better or worse than rendezvous, is open to
implementation also. I do know that for pthread supported
platforms, GNAT does use pthread_cond_signal and pthread_cond_wait,
which are open to the problems presented (see the source file
for system.task_primitives.operations.adb).  The O/S will determine
whether or not one or multiple threads awaken however (it might be that
Linux queues them for example). But if you are taking portability
into mind, you should assume that all threads awaken (only one will
stay awake of course, because only one thread can win -- like
the movie "Highlander" -- "there can only be one"). ;-)

Is the rendezvous better?  I don't know, because I didn't dig that
closely into the sources. But potentially, I would think that with
a queue being used, it could be implemented such that only the task
on the front of the queue gets "signalled" to continue (each task
would then need its own "condition variable").

>> It also guarantees "order". With the protected object approach a
>> "Johnnie come lately" task could gain access while already blocked
>> tasks are waiting to gain access -- destroying the waiting line
>> sequence. This may create some confusing to read "output".
> 
> 
> If you need to guarantee order for a protected operation it should be an 
> entry. This guarantees the same order as for a task entry.

OK then, this makes the distinction between rendezvous and protected
objects unimportant in the "ordering" context. It also probably kills
the "efficiency" debate, because I would assume that the same
implmentation would be used for both.

-- 
Warren W. Gay VE3WWG
http://home.cogeco.ca/~ve3wwg




^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: new_line in a put_line
  2002-12-05  9:36                 ` Dmitry A. Kazakov
@ 2002-12-05 22:40                   ` tmoran
  0 siblings, 0 replies; 30+ messages in thread
From: tmoran @ 2002-12-05 22:40 UTC (permalink / raw)


> >  Then you should use a task.
> The problem (maybe a mental one) is than one would say - what a
> monster for such a simple thing!
  A second task and a rendezvous does seem a little large.  That's
why the controlled-object-critical-region idiom is often preferred.



^ permalink raw reply	[flat|nested] 30+ messages in thread

end of thread, other threads:[~2002-12-05 22:40 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-12-05  6:28 new_line in a put_line Grein, Christoph
2002-12-05 14:19 ` Stephen Leake
  -- strict thread matches above, loose matches on Subject: below --
2002-12-05  6:16 Grein, Christoph
2002-12-05  9:44 ` Dmitry A. Kazakov
2002-12-04 10:03 Grein, Christoph
2002-12-03 11:52 Grein, Christoph
2002-12-04  9:39 ` Fraser Wilson
2002-12-02  5:36 Vlad
2002-12-02  9:47 ` Preben Randhol
2002-12-02 17:04   ` Frank J. Lhota
2002-12-05 11:10     ` Preben Randhol
2002-12-02 10:14 ` Dmitry A. Kazakov
2002-12-02 14:57 ` Matthew Heaney
2002-12-03 11:33   ` Fraser Wilson
2002-12-03 15:01     ` Dmitry A. Kazakov
2002-12-04  9:31       ` Fraser Wilson
2002-12-04 14:10         ` Dmitry A. Kazakov
2002-12-04 15:23           ` Robert A Duff
2002-12-04 16:15             ` Dmitry A. Kazakov
2002-12-04 18:11               ` tmoran
2002-12-04 20:21                 ` Simon Wright
2002-12-05  9:36                 ` Dmitry A. Kazakov
2002-12-05 22:40                   ` tmoran
2002-12-04 15:25           ` Stephen Leake
2002-12-04 16:55             ` Jeffrey Carter
2002-12-04 17:24               ` Stephen Leake
2002-12-04 17:43               ` Warren W. Gay VE3WWG
2002-12-05  1:31                 ` Jeffrey Carter
2002-12-05 18:11                   ` Warren W. Gay VE3WWG
2002-12-02 15:49 ` Robert A Duff

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