there is something I don’t understand with your second example:
it seems that in the end, J gets lower than 0, so a Constraint_Error is raised in procedure Get, but no error message is displayed.
So if I understand well, the line
exit when A_Job < 1;
is useless because anyway the task exit because of Constraint_Error.
Try using this as the body of Get:
Put_Line (“before: ” & J’Img);
Job := J;
J := J – 1;
Put_Line (“after: ” & J’Img);
You’ll see that J never goes below zero.
But you’re right, it’s not really pretty. I’ll fix it to make it more clear. Thanks for pointing it out.
edit: Blarg.. Can’t even read my own output any longer. It does go below 0 – sheesh. Fix on its way!
There we go! Thanks to Apoptose for catching that nasty little bug.
Prior to the fix I was completely abusing the fact that a task can die silently if exceptions aren’t handled. The worst part about that is that it is described here:
And I read that a short while ago when I started mucking around with the Ada.Task_* packages. My memory is failing me!
No problemo, I’m glad I understand better how the code works now.
I know you have done some Haskell, do you plan to write some kind of comparison between concurrent programming in Ada and in Haskell?
I know there’s a book on its way about concurrent programming in Haskell:
I do plan on buying that book, but whether or not I’ll ever reach a level of Haskell competence to be able to compare its features to Ada I honestly don’t know.
What I do know is that both Ada and Haskell are awesomely nice languages.
I just made a similar implementation of dispatching jobs in parallel.
See code at http://shootout.alioth.debian.org/u64q/program.php?test=regexdna&lang=gnat&id=3
in procedure Parallel_Count.
There is no need of the package Ada.Task_Identification;
After completion of job, the returning worker gives its job_nbr to the dispatcher.
Improvement in speed on a 4-core is limited to a factor of 3 wrt to single core.
9 jobs => 2 rounds with 4 cores + 1 round with 1 core. = 3
That’s some pretty awesome code you got going there! Thanks for linking it.
I used the Ada.Task_Identification package because it clearly shows that different tasks have different internal id’s, and it does so in a very beginner friendly way.
Also it’s nice to learn about the existence of the Ada.Task_* packages. They are very handy.
Neat! I find the scheme clea, the example instructive,
and well explained.
Can I make some comments about the choice of identifiers?
That’s from the perspective of a reader, totally subjective, of course.
It reflects what had me a little confused at first, looking at the source
(not the explanation). For example, there are:
Jobs (Positive), Job (Natural), Jobs (protected), A_Job (Natural),
Job as an immutable loop variable. And none of these is, well,
if I may, a job (task). They are jobs’ numbers, though, as the
This might all appear nitpicky, I guess. I always found good names helpful
for understanding source from source, which is why…
The following is just what came to my mind after reading from top to bottom,
and back. It’s not placed here to suggest replacements or anything,
but to back up my nagging with something constructive. Not necessarily
good, but hopefully constructive.
subtype Job_Number is Natural;
What does the protected object do? Looking at the source, it has
“Jobs.Get”, so I’d have thought that the caller gets a job. It does
get a job’s number, just like a runner gets one, or like someone
waiting in some public office gets one. Hence, maybe,
protected Dispenser …;
protected Bowl …; — or something less pictorial or …
Then, de-Generalize the name “Get” so that the name of this
procedure conveys some of what to expect when calling it:
where the out actual parameters’ names will designate the
job number variables declared in the task bodies.
Hope you don’t mind a somewhat missionary rant.
Awesome. Let me repeat that: Awesome. Thank you very much for your constructive advice. I’m so utterly bad at coming up with names for identifiers, so having someone actually giving me some solid suggestions is a real boon.
I’ll look into updating the code/examples to reflect the thoughts from your “missionary rant”.
Someone should write an article on good naming schemes for identifiers. hint hint.
[...] in may I wrote an article called Concurrent Ada Programming. It was meant as an introduction to the wonderful world of Ada tasking and protected objects, and [...]
What happened to the distinction between parallelism and concurrency?
I’m not sure I understand your question Janus. Did something happen with the distinction?
To me concurrency is >= 2 threads are making progres (not necessarily in parallel), whereas parallelism is when >= 2 threads are making progress at the _same time_.
One could say that Ada have awesome tools for concurrency, and these tools might result in a program where the threads execute in parallel.
Or am I missing something?
Email (Not published)