* 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 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-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
* 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 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 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: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
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