comp.lang.ada
 help / color / mirror / Atom feed
* Strange behavior
@ 2014-09-05 19:30 Laurent
  2014-09-05 19:47 ` sbelmont700
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Laurent @ 2014-09-05 19:30 UTC (permalink / raw)


Hi

I have a strange behavior with this simple tasking example:

https://github.com/Chutulu/chapter_17.git

with Ada.Text_IO;
procedure Two_Cooperating_Tasks is
   
   task type Simple_Task (Message : Character; How_Many : Positive);
   
   task body Simple_Task is
      
   begin -- Simple_Task
      
      for Count in 1 .. How_Many loop
         Ada.Text_IO.Put ("Hello from Task " & Message);
         Ada.Text_IO.New_Line;
         delay 0.1;
      end loop;
      
   end Simple_Task;
   
   Task_A : Simple_Task (Message => 'A', How_Many => 5);
   Task_B : Simple_Task (Message => 'B', How_Many => 5);
   
begin -- Two_Cooperating_Tasks
   
   null;
   
end Two_Cooperating_Tasks;

when I run the program I get this:

/Volumes/Kingston/GPS/Chapter 17/Build/two_cooperating_tasks
Hello from Task BHello from Task A

Hello from Task AHello from Task B

Hello from Task A
Hello from Task B
Hello from Task A
Hello from Task B
Hello from Task AHello from Task B

[2014-09-05 21:17:14] process terminated successfully, elapsed time: 00.68s

If the program runs again the result is again different.

The order of the tasks executing is random and that is ok but why  is it changing and why is the New_Line zapped?

Using gnat 2014 on MacOS 10.9

Thanks

Laurent 


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

* Re: Strange behavior
  2014-09-05 19:30 Strange behavior Laurent
@ 2014-09-05 19:47 ` sbelmont700
  2014-09-05 20:05   ` Laurent
  2014-09-05 20:23 ` Jeffrey Carter
  2014-09-05 20:34 ` Robert A Duff
  2 siblings, 1 reply; 10+ messages in thread
From: sbelmont700 @ 2014-09-05 19:47 UTC (permalink / raw)


On Friday, September 5, 2014 3:30:51 PM UTC-4, Laurent wrote:
> 
> The order of the tasks executing is random and that is ok but why  is it changing and why is the New_Line zapped?
> 

Because the order of the tasks is random; what else would you expect?  The new lines aren't zapped, its just that the OS switches tasks after the Put_Line but before the New_Line.  You get it back the next time, hence the blank space (two CR/LFs in a row).

-sb


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

* Re: Strange behavior
  2014-09-05 19:47 ` sbelmont700
@ 2014-09-05 20:05   ` Laurent
  2014-09-06  0:53     ` Dennis Lee Bieber
  0 siblings, 1 reply; 10+ messages in thread
From: Laurent @ 2014-09-05 20:05 UTC (permalink / raw)


Am Freitag, 5. September 2014 21:47:19 UTC+2 schrieb sbelm...@gmail.com:
> On Friday, September 5, 2014 3:30:51 PM UTC-4, Laurent wrote:
> 
> > 
> 
> > The order of the tasks executing is random and that is ok but why  is it changing and why is the New_Line zapped?
> 
> > 
> 
> 
> 
> Because the order of the tasks is random; what else would you expect?  The new lines aren't zapped, its just that the OS switches tasks after the Put_Line but before the New_Line.  You get it back the next time, hence the blank space (two CR/LFs in a row).
> 
> 
> 
> -sb

Because the sample run in the book looks a bit different. More like this:

Hello from Task A
Hello from Task B 
Hello from Task A
Hello from Task B 
Hello from Task A 
Hello from Task B 
Hello from Task A 
Hello from Task B 
Hello from Task A
Hello from Task B 

or 

Hello from Task B 
Hello from Task A
Hello from Task B 
Hello from Task A
.
.
.

No sudden inversion of the order. 
What has the switching of the tasks to do with this? Shouldn't the delay 0,1 prevent that? That's an eternity for a computer. The New_Line is part of the task? Or is the OS trying to do me a favor by distributing the task on different cores which produces garbage? 

Sorry for the noob questions

The more I learn about programming the more I understand that I don't even have scratched the surface.

Thanks

Laurent


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

* Re: Strange behavior
  2014-09-05 19:30 Strange behavior Laurent
  2014-09-05 19:47 ` sbelmont700
@ 2014-09-05 20:23 ` Jeffrey Carter
  2014-09-05 20:48   ` Robert A Duff
  2014-09-05 20:34 ` Robert A Duff
  2 siblings, 1 reply; 10+ messages in thread
From: Jeffrey Carter @ 2014-09-05 20:23 UTC (permalink / raw)


On 09/05/2014 12:30 PM, Laurent wrote:
>       
>    begin -- Simple_Task
>       
>       for Count in 1 .. How_Many loop
>          Ada.Text_IO.Put ("Hello from Task " & Message);
>          Ada.Text_IO.New_Line;
>          delay 0.1;
>       end loop;
>       
>    end Simple_Task;
>    
>    Task_A : Simple_Task (Message => 'A', How_Many => 5);
>    Task_B : Simple_Task (Message => 'B', How_Many => 5);
> 
> /Volumes/Kingston/GPS/Chapter 17/Build/two_cooperating_tasks
> Hello from Task BHello from Task A
> 
> Hello from Task AHello from Task B
> 
> Hello from Task A
> Hello from Task B
> Hello from Task A
> Hello from Task B
> Hello from Task AHello from Task B
> 
> [2014-09-05 21:17:14] process terminated successfully, elapsed time: 00.68s
> 
> If the program runs again the result is again different.
> 
> The order of the tasks executing is random and that is ok but why  is it changing and why is the New_Line zapped?

On most modern computers, 2 tasks can run in parallel, so apparently the system
is queuing up high-level requests for output and performing them sequentially.
It would not be uncommon, then, for the 2 calls to Put to result in the 2
messages together, followed by the 2 calls to New_line resulting in a blank
line. It's surprising that you got so many cases where all the output from one
task is followed by all the output from the other.

Note that this behavior isn't guaranteed by the language. At a low level, output
is done character by character, and nothing requires that the Ada run time or OS
queue up requests at a higher level. So it would be perfectly legal to get
results such as

HellHelo lofr fomr

-- 
Jeff Carter
"It's all right, Taggart. Just a man and a horse being hung out there."
Blazing Saddles
34




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

* Re: Strange behavior
  2014-09-05 19:30 Strange behavior Laurent
  2014-09-05 19:47 ` sbelmont700
  2014-09-05 20:23 ` Jeffrey Carter
@ 2014-09-05 20:34 ` Robert A Duff
  2014-09-05 20:40   ` Laurent
  2 siblings, 1 reply; 10+ messages in thread
From: Robert A Duff @ 2014-09-05 20:34 UTC (permalink / raw)


Laurent <daemon2@internet.lu> writes:

> with Ada.Text_IO;
> procedure Two_Cooperating_Tasks is
>    
>    task type Simple_Task (Message : Character; How_Many : Positive);
>    
>    task body Simple_Task is
>       
>    begin -- Simple_Task
>       
>       for Count in 1 .. How_Many loop
>          Ada.Text_IO.Put ("Hello from Task " & Message);
>          Ada.Text_IO.New_Line;
>          delay 0.1;
>       end loop;
>       
>    end Simple_Task;
>    
>    Task_A : Simple_Task (Message => 'A', How_Many => 5);
>    Task_B : Simple_Task (Message => 'B', How_Many => 5);
>    
> begin -- Two_Cooperating_Tasks
>    
>    null;
>    
> end Two_Cooperating_Tasks;

The above causes erroneous execution, which means that anything can
happen.  Two tasks are writing to standard output without proper
synchronization.  (I would prefer the language defined each output
call to be atomic, but it doesn't.  And that wouldn't help much in your
example, because you have two calls, Put and New_Line.  You could
combine those into a single Put_Line, by the way.)

If you have only one processor, then the output shown in the text is
likely to happen.  But you can't depend on that.  And anyway, nowadays
you almost certainly have more than one processor, so the tasks are
executing in parallel.

Synchronization via delay statements is a wrong way to do.

- Bob


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

* Re: Strange behavior
  2014-09-05 20:34 ` Robert A Duff
@ 2014-09-05 20:40   ` Laurent
  2014-09-06  1:10     ` Dennis Lee Bieber
  0 siblings, 1 reply; 10+ messages in thread
From: Laurent @ 2014-09-05 20:40 UTC (permalink / raw)


Am Freitag, 5. September 2014 22:34:17 UTC+2 schrieb Robert A Duff:
> Laurent writes:
> 
> 
> 
> > with Ada.Text_IO;
> 
> > procedure Two_Cooperating_Tasks is
> 
> >    
> 
> >    task type Simple_Task (Message : Character; How_Many : Positive);
> 
> >    
> 
> >    task body Simple_Task is
> 
> >       
> 
> >    begin -- Simple_Task
> 
> >       
> 
> >       for Count in 1 .. How_Many loop
> 
> >          Ada.Text_IO.Put ("Hello from Task " & Message);
> 
> >          Ada.Text_IO.New_Line;
> 
> >          delay 0.1;
> 
> >       end loop;
> 
> >       
> 
> >    end Simple_Task;
> 
> >    
> 
> >    Task_A : Simple_Task (Message => 'A', How_Many => 5);
> 
> >    Task_B : Simple_Task (Message => 'B', How_Many => 5);
> 
> >    
> 
> > begin -- Two_Cooperating_Tasks
> 
> >    
> 
> >    null;
> 
> >    
> 
> > end Two_Cooperating_Tasks;
> 
> 
> 
> The above causes erroneous execution, which means that anything can
> 
> happen.  Two tasks are writing to standard output without proper
> 
> synchronization.  (I would prefer the language defined each output
> 
> call to be atomic, but it doesn't.  And that wouldn't help much in your
> 
> example, because you have two calls, Put and New_Line.  You could
> 
> combine those into a single Put_Line, by the way.)
> 
> 
> 
> If you have only one processor, then the output shown in the text is
> 
> likely to happen.  But you can't depend on that.  And anyway, nowadays
> 
> you almost certainly have more than one processor, so the tasks are
> 
> executing in parallel.
> 
> 
> 
> Synchronization via delay statements is a wrong way to do.
> 
> 
> 
> - Bob

Yes I understand that. The following examples in the book actually are about this problem and that's the introduction for the protected types. I was just astonished that a so simple program can already behave so unpredictable. Ok the book was written in 1998 so at this time the result was probably different.

Thanks to all for the enlightenment

Laurent


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

* Re: Strange behavior
  2014-09-05 20:23 ` Jeffrey Carter
@ 2014-09-05 20:48   ` Robert A Duff
  0 siblings, 0 replies; 10+ messages in thread
From: Robert A Duff @ 2014-09-05 20:48 UTC (permalink / raw)


Jeffrey Carter <spam.jrcarter.not@spam.not.acm.org> writes:

>...So it would be perfectly legal to get
> results such as
>
> HellHelo lofr fomr

Yes.  Also, a conforming implementation of Ada could print "Happy
Birthday", although the output you showed above is more likely.
It's also likely to drop characters, because some software is
incrementing an index into a buffer and putting a character at
that index.  And we all know what happens when two tasks
increment an index simultaneously without synchronization.

- Bob


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

* Re: Strange behavior
  2014-09-05 20:05   ` Laurent
@ 2014-09-06  0:53     ` Dennis Lee Bieber
  2014-09-06  1:35       ` Adam Beneschan
  0 siblings, 1 reply; 10+ messages in thread
From: Dennis Lee Bieber @ 2014-09-06  0:53 UTC (permalink / raw)


On Fri, 5 Sep 2014 13:05:05 -0700 (PDT), Laurent <daemon2@internet.lu>
declaimed the following:

>
>No sudden inversion of the order. 
>What has the switching of the tasks to do with this? Shouldn't the delay 0,1 prevent that? That's an eternity for a computer. The New_Line is part of the task? Or is the OS trying to do me a favor by distributing the task on different cores which produces garbage? 
>
	The delay statement provides the OS a known point at which a task
switch CAN (and likely will) take place.

	However, a task switch can take place on ANY operation that hands off
to the OS -- that means any I/O call is a point at which a task switch can
occur. More so with a hyperthreaded/multi-core processor, since a task that
has just invoked an I/O operation is blocked waiting for that I/O to
complete; the other task is free to run at that time (on any core).

	The delay only ensures you get some sort of alternation. Without a
delay, on a single core, and with a fast I/O system, it is possible that
one task could run to completion before the other task even started to run.
-- 
	Wulfraed                 Dennis Lee Bieber         AF6VN
    wlfraed@ix.netcom.com    HTTP://wlfraed.home.netcom.com/


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

* Re: Strange behavior
  2014-09-05 20:40   ` Laurent
@ 2014-09-06  1:10     ` Dennis Lee Bieber
  0 siblings, 0 replies; 10+ messages in thread
From: Dennis Lee Bieber @ 2014-09-06  1:10 UTC (permalink / raw)


On Fri, 5 Sep 2014 13:40:29 -0700 (PDT), Laurent <daemon2@internet.lu>
declaimed the following:


>
>Yes I understand that. The following examples in the book actually are about this problem and that's the introduction for the protected types. I was just astonished that a so simple program can already behave so unpredictable. Ok the book was written in 1998 so at this time the result was probably different.

	1998 was the era of the Pentium II with MMX (multimedia extension)
operations; a hyper-threaded Pentium 4 didn't show up until 2002, in the
hands of the rich and powerful.

	While the Ada language spec may only require physical I/O at the
character level, I suspect many compilers/run-times are deferring to O/S
I/O functions, and those functions may treat a full string as an
indivisible output operation... but separating a string Put from a New_Line
makes that /two/ I/O operations, and the O/S is free to task switch between
them.
-- 
	Wulfraed                 Dennis Lee Bieber         AF6VN
    wlfraed@ix.netcom.com    HTTP://wlfraed.home.netcom.com/


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

* Re: Strange behavior
  2014-09-06  0:53     ` Dennis Lee Bieber
@ 2014-09-06  1:35       ` Adam Beneschan
  0 siblings, 0 replies; 10+ messages in thread
From: Adam Beneschan @ 2014-09-06  1:35 UTC (permalink / raw)


On Friday, September 5, 2014 5:53:11 PM UTC-7, Dennis Lee Bieber wrote:

> 	However, a task switch can take place on ANY operation that hands off
> to the OS -- that means any I/O call is a point at which a task switch can
> occur. 

Just to clarify, task switches can take place at any time, not just when an OS operation occurs, depending on the task dispatching policy.  For a preempting policy, a lower-priority task can be preempted by a higher-priority task as soon as something happens to make the higher-priority task ready to run; the task being preempted doesn't need to be anywhere near an OS call.  For a round-robin policy, a task can also be preempted by a task of the same priority, at any time.  

The Intel i960 processor supports time slicing, in which there's a timer that counts down, and when it hits 0, the processor will automatically switch to another process with the same priority.  That process is then allowed to execute for a certain time, but when its timer hits 0, the processor will switch again to another process, possibly the first one.  There's no OS involvement.  This is one of the processors ICC Ada is targeted to, and we took advantage of that feature; this was done back when Ada 83 was the standard, and there were no task dispatching policies and the dispatching mechanisms were pretty much left up to the implementor with just a few requirements.  However, I believe that the Round_Robin_Within_Priorities policy (since Ada 2005) is essentially the same as how this processor works; it might be exactly the same, but there could be some nuances that would make it a little different--I haven't studied it.

                             -- Adam


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

end of thread, other threads:[~2014-09-06  1:35 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-09-05 19:30 Strange behavior Laurent
2014-09-05 19:47 ` sbelmont700
2014-09-05 20:05   ` Laurent
2014-09-06  0:53     ` Dennis Lee Bieber
2014-09-06  1:35       ` Adam Beneschan
2014-09-05 20:23 ` Jeffrey Carter
2014-09-05 20:48   ` Robert A Duff
2014-09-05 20:34 ` Robert A Duff
2014-09-05 20:40   ` Laurent
2014-09-06  1:10     ` Dennis Lee Bieber

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