As Eliot implied in another reply, Pharo has #processPreemptionYields
set to true, which means that any time a higher priority process
preempts, the current process will be moved to the back of the queue.
Yes this is explained in the next chapter.
At least I cannot.
So in the case above, after p2 signals the semaphore, if a timer was
delivered or keystroke pressed, p2 would be suspended and moved to the
back of the queue. When the timer / keystroke / etc. had finished
processing p1 would be at the front of the queue and would complete
first.
Since time and input events are (for practical purposes) unpredictable
it means that the execution order of processes at a given priority is
also unpredictable.
While this isn't likely to happen in the example above, I have seen it
regularly with TaskIt and multiple entries being run concurrently.
I agree with Eliot that changing #processPreemptionYields to true by
default would be an improvement in Pharo. It would make it easier to
predict what is happening in a complex environment.
If this would be that easy. :)
Now what would be a consequence: we should revisit all the processes of the system
and understand if/where they should yield. Because now there is an implicit yield.
So in an ideal world the new semantics is probably better. Now are we ready to get new bugs
and chase them when an old logic like for example an hidden process in calypso worked
under the assumption that it was implicitly yielding after preemption?
This is the question that we asked ourselves and we do not really know.
So far Pharo worked this way during 12 years with this semantics (I does not mean that we cannot
change because of our Motto - but the point is to understand the impact and control).
Contrary to what people may think we are not changing without assessing impact.
So to us this is not an easy decision (while doing it take one single line of one assignment).
Running the following variant, and then typing in to another window,
I like the idea of the input to show the interaction between processes.
I will investigate what I can do with it.
demonstrates the behaviour:
| semaphore p1 p2 |
semaphore := Semaphore new.
[ 100 timesRepeat: [
p1 := [ | z |
semaphore wait.
z := SmallInteger maxVal.
10000000 timesRepeat: [ z := z + 1 ].
'p1' crTrace ] fork.
p2 := [ | z | 1 second wait.
semaphore signal.
z := SmallInteger maxVal.
10000000 timesRepeat: [ z := z + 1 ].
'p2' crTrace ] fork.
1 second wait.
] ] fork.
The tail of transcript:
'p2'
'p1'
'p1'
'p1'
'p1'
'p2'
'p2'
'p2'
'p1'
'p1'
'p2'
'p1'
'p2'
'p2'
'p1'
'p1'
'p2'
'p1'
Cheers,
Alistair