Pharo-dev
By thread
pharo-dev@lists.pharo.org
By month
Messages by month
- ----- 2026 -----
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
January 2020
- 290 messages
Re: [Pharo-dev] about signal
by Alistair Grant
Hi Sven,
In line below...
Cheers,
Alistair
(on phone)
On Sun., 12 Jan. 2020, 13:00 Sven Van Caekenberghe, <sven(a)stfx.eu> wrote:
>
> Hi Alistair,
>
> > On 12 Jan 2020, at 09:33, Alistair Grant <akgrant0710(a)gmail.com> wrote:
> >
> >
> > 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.
>
> I don't understand, in your second paragraph you say 'Pharo has #processPreemptionYields set to true' and now you say it should become the default. Is that already the case or not then ?
Oops, typo, sorry. I meant to say 'false'. (I shouldn't ever reply in a hurry).
>
> > Running the following variant, and then typing in to another window,
> > demonstrates the behaviour:
>
> I am not sure what you want to demonstrate: that it is totally random depending on external factors ;-) ?
If processPreemptionYields false the output should be:
...
p2
p1
p2
p1
p2
p1
...
i.e. it is regular. What we're actually seeing is:
...
'p1'
'p2'
'p1'
'p2'
'p2'
...
Which showing that p2 might get to signal multiple times before p1
gets to complete a single loop.
> Which is pretty bad: how should semaphores be used (safely) ? What are good examples of real world correct semaphore usage ?
Given a set of processes at the same priority the amount of time
allocated to any one of the processes is unpredictable.
All the semaphore usage is working as described. My point wasn't that
the semaphores are being used incorrectly, but that you can't make
assumptions about the order in which processes will complete if they
are CPU bound.
> Right now, all the explanations around scheduling of processes and their priorities make it seem as if the answer is 'it all depends' and 'there is no way to be 100% sure what will happen'.
The semaphore operations are clear, but which process, within a single
process priority, gets the most CPU time is less so.
HTH,
Alistair
Jan. 12, 2020
Re: [Pharo-dev] about signal
by Alistair Grant
Hi Stef,
On Sun, 12 Jan 2020 at 11:28, ducasse <stepharo(a)netcourrier.com> wrote:
>
> Hi alistair
>
>
> Hi
>
> I wanted to explain
>
> | semaphore p1 p2 |
> semaphore := Semaphore new.
> p1 := [ semaphore wait.
> 'p1' crTrace ] fork.
>
> p2 := [semaphore signal.
> 'p2' crTrace ] fork.
>
> displays p2 and p1.
> but I would like explain clearly but it depends on the semantics of signal.
>
>
> The way this is phrased seems to imply that 'p2' will always be
> displayed before 'p1', however in Pharo this is not guaranteed (when
> the processes are at the same priority, as they are this example).
>
>
> No this is not what I implied.
> I will reread and rephrase the chapters.
>
> 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.
> What you should see is that we cannot explain everything in a single chapter.
> At least I cannot.
Agreed. Maybe just a footnote indicating that process scheduling will
be explained in later chapters.
> 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.
As Sven kindly pointed out, I meant to say set
#processPreemptionYields to false.
> 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).
I also wasn't implying that we just go ahead and change it. But if it
is a possibility then I'll try changing it in my image and see how it
helps with tracking down inter-process interactions that we're
currently experiencing, and if it does introduce any showstopper
issues.
Cheers,
Alistair
Jan. 12, 2020
Re: [Pharo-dev] about signal
by Sven Van Caekenberghe
Hi Alistair,
> On 12 Jan 2020, at 09:33, Alistair Grant <akgrant0710(a)gmail.com> wrote:
>
> On Thu, 9 Jan 2020 at 13:01, ducasse <stepharo(a)netcourrier.com> wrote:
>>
>> Hi
>>
>> I wanted to explain
>>
>> | semaphore p1 p2 |
>> semaphore := Semaphore new.
>> p1 := [ semaphore wait.
>> 'p1' crTrace ] fork.
>>
>> p2 := [semaphore signal.
>> 'p2' crTrace ] fork.
>>
>> displays p2 and p1.
>> but I would like explain clearly but it depends on the semantics of signal.
>
> The way this is phrased seems to imply that 'p2' will always be
> displayed before 'p1', however in Pharo this is not guaranteed (when
> the processes are at the same priority, as they are this example).
>
> 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.
>
> 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.
I don't understand, in your second paragraph you say 'Pharo has #processPreemptionYields set to true' and now you say it should become the default. Is that already the case or not then ?
> Running the following variant, and then typing in to another window,
> demonstrates the behaviour:
I am not sure what you want to demonstrate: that it is totally random depending on external factors ;-) ?
Which is pretty bad: how should semaphores be used (safely) ? What are good examples of real world correct semaphore usage ?
Right now, all the explanations around scheduling of processes and their priorities make it seem as if the answer is 'it all depends' and 'there is no way to be 100% sure what will happen'.
Sven
> | 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
Jan. 12, 2020
Re: [Pharo-dev] about signal
by Sven Van Caekenberghe
Hi Ben,
> On 11 Jan 2020, at 10:50, Ben Coman <btc(a)openinworld.com> wrote:
>
>
>
> On Sat, 11 Jan 2020 at 06:31, Sven Van Caekenberghe <sven(a)stfx.eu> wrote:
> Hi Ben,
>
> Great approach, though I would make one change to make your example completely copy/paste runnable.
>
> Stef's original example:
>
> | trace semaphore p1 p2 |
>
> semaphore := Semaphore new.
>
> trace := [ :message |
> ('[{1}] {2}' format: { Processor activeProcess priority. message }) crLog ].
>
> p1 := [
> semaphore wait.
> trace value: 'Process 1' ] fork.
>
> p2 := [
> semaphore signal.
> trace value: 'Process 2' ] fork.
>
> trace value: 'Original process pre-yield'.
> Processor yield.
> trace value: 'Original process post-yield'.
>
> Gives:
>
> '[40] Original process pre-yield'
> '[40] Process 2'
> '[40] Original process post-yield'
> '[40] Process 1'
>
> But not running the yield section gives:
>
> '[40] Process 2'
> '[40] Process 1'
>
> which is an identical result if the 'Original process' traces are filtered out.
>
>
> From this it would seem that the code in p2 continues after signal and only later does p1 get past its wait.
>
> Yes, a #signal does not transfer execution unless the waiting-process that received the signal is a higher priority.
> Within the same priority, it just makes waiting-process runnable, and the highest-priority-runnable-process is the one that is run.
OK, I can understand that, the question remains what happens when the processes have equal priorities.
> Playing with the priorities we can change that order (apparently);
>
> | trace semaphore p1 p2 |
>
> semaphore := Semaphore new.
>
> trace := [ :message |
> ('[{1}] {2}' format: { Processor activeProcess priority. message }) crLog ].
>
> p1 := [
> semaphore wait.
> trace value: 'Process 1' ] forkAt: 30.
>
> p2 := [
> semaphore signal.
> trace value: 'Process 2' ] forkAt: 20.
>
> Gives:
>
> '[30] Process 1'
> '[20] Process 2'
>
> Again, the yield section makes no difference. So something else happened.
>
> The yield made no difference because it only facilitates other processes at-the-SAME-priority getting a chance to run.
> Yield doesn't put the current-process to sleep, it just moves the process to the back of its-priority-runQueue. It gets to run again before any lower priority process gets a chance to run.
>
> Yielding will never allow a lower-priority-process to run.
> For a lower-priority process to run, the current-process needs to sleep rather than yield.
These are clear statements.
> Compare...
> | trace semaphore p1 p2 |
> semaphore := Semaphore new.
> trace := [ :message | ('@{1} {2}' format: { Processor activePriority. message }) crLog ].
> p1 := [
> trace value: 'Process 1a waits for signal on semaphore'.
> semaphore wait.
> trace value: 'Process 1b received signal' ] forkAt: 30.
> p2 := [
> trace value: 'Process 2a signals semaphore'.
> semaphore signal.
> trace value: 'Process 2b continues' ] forkAt: 20.
> trace value: 'Original process pre-yield'.
> Processor yield.
> trace value: 'Original process post-yield'.
>
> ==>
> '@40 Original process pre-yield'
> '@40 Original process post-yield'
> '@30 Process 1a waits for signal on semaphore'
> '@20 Process 2a signals semaphore'
> '@30 Process 1b received signal'
> '@20 Process 2b continues'
>
> with...
> | trace semaphore p1 p2 |
> semaphore := Semaphore new.
> trace := [ :message | ('@{1} {2}' format: { Processor activePriority. message }) crLog ].
> p1 := [
> trace value: 'Process 1a waits for signal on semaphore'.
> semaphore wait.
> trace value: 'Process 1b received signal' ] forkAt: 30.
> p2 := [
> trace value: 'Process 2a signals semaphore'.
> semaphore signal.
> trace value: 'Process 2b continues' ] forkAt: 20.
> trace value: 'Original process pre-delay'.
> 1 milliSecond wait.
> trace value: 'Original process post-delay'.
>
> ==>
> '@40 Original process pre-delay'
> '@30 Process 1a waits for signal on semaphore'
> '@20 Process 2a signals semaphore'
> '@30 Process 1b received signal'
> '@20 Process 2b continues'
> '@40 Original process post-delay'
OK, good example: I think/hope I understand.
Now, these further examples only strengthen my believe that it is simply impossible to talk about semaphores without talking about (the complexities) of process scheduling.
Semaphores exist as a means to coordinate processes, hence when using them you have to understand what (will) happen, and apparently that is quite complex.
In any case, thanks again for the explanations,
Sven
> Stef, on further consideration I think your first examples should not-have p1 and p2 the same priority.
> Scheduling of same-priority processes and how they interact with the UI thread is an extra level of complexity that may be better done shortly after.
> Not needing to trace "Original process" in the first example gives less for the reader to digest
>
> So your first example might compare...
> | trace semaphore p1 p2 |
> semaphore := Semaphore new.
> trace := [ :message | ('@{1} {2}' format: { Processor activePriority. message }) crLog ].
> p1 := [
> trace value: 'Process 1a waits for signal on semaphore'.
> semaphore wait.
> trace value: 'Process 1b received signal' ] forkAt: 20.
> p2 := [
> trace value: 'Process 2a signals semaphore'.
> semaphore signal.
> trace value: 'Process 2b continues' ] forkAt: 30.
>
> ==>
> '@30 Process 1a waits for signal on semaphore'
> '@20 Process 2a signals semaphore'
> '@30 Process 1b received signal'
> '@20 Process 2b continues'
>
>
> with the priority order swapped...
> | trace semaphore p1 p2 |
> semaphore := Semaphore new.
> trace := [ :message | ('@{1} {2}' format: { Processor activePriority. message }) crLog ].
> p1 := [
> trace value: 'Process 1a waits for signal on semaphore'.
> semaphore wait.
> trace value: 'Process 1b received signal' ] forkAt: 30.
> p2 := [
> trace value: 'Process 2a signals semaphore'.
> semaphore signal.
> trace value: 'Process 2b continues' ] forkAt: 20.
>
> ==>
> '@30 Process 2a signals semaphore'
> '@30 Process 2b continues'
> '@20 Process 1a waits for signal on semaphore'
> '@20 Process 1b received signal'
>
>
> cheers -ben
Jan. 12, 2020
[Pharo 8.0] Build #1103: 5466-Better-Semaphore-class-comment
by ci-pharo-ci-jenkins2@inria.fr
There is a new Pharo build available!
The status of the build #1103 was: SUCCESS.
The Pull Request #5467 was integrated: "5466-Better-Semaphore-class-comment"
Pull request url: https://github.com/pharo-project/pharo/pull/5467
Issue Url: https://github.com/pharo-project/pharo/issues/5466
Build Url: https://ci.inria.fr/pharo-ci-jenkins2/job/Test%20pending%20pull%20request%2…
Jan. 12, 2020
Re: [Pharo-dev] about signal
by ducasse
Hi alistair
>>
>> Hi
>>
>> I wanted to explain
>>
>> | semaphore p1 p2 |
>> semaphore := Semaphore new.
>> p1 := [ semaphore wait.
>> 'p1' crTrace ] fork.
>>
>> p2 := [semaphore signal.
>> 'p2' crTrace ] fork.
>>
>> displays p2 and p1.
>> but I would like explain clearly but it depends on the semantics of signal.
>
> The way this is phrased seems to imply that 'p2' will always be
> displayed before 'p1', however in Pharo this is not guaranteed (when
> the processes are at the same priority, as they are this example).
No this is not what I implied.
I will reread and rephrase the chapters.
> 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.
What you should see is that we cannot explain everything in a single 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
Jan. 12, 2020
Re: [Pharo-dev] about signal
by Alistair Grant
On Thu, 9 Jan 2020 at 13:01, ducasse <stepharo(a)netcourrier.com> wrote:
>
> Hi
>
> I wanted to explain
>
> | semaphore p1 p2 |
> semaphore := Semaphore new.
> p1 := [ semaphore wait.
> 'p1' crTrace ] fork.
>
> p2 := [semaphore signal.
> 'p2' crTrace ] fork.
>
> displays p2 and p1.
> but I would like explain clearly but it depends on the semantics of signal.
The way this is phrased seems to imply that 'p2' will always be
displayed before 'p1', however in Pharo this is not guaranteed (when
the processes are at the same priority, as they are this example).
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.
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.
Running the following variant, and then typing in to another window,
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
Jan. 12, 2020
[Pharo 9.0] Build #5: Fixing FFI Error in Cairo
by ci-pharo-ci-jenkins2@inria.fr
There is a new Pharo build available!
The status of the build #5 was: FAILURE.
The Pull Request #5454 was integrated: "Fixing FFI Error in Cairo"
Pull request url: https://github.com/pharo-project/pharo/pull/5454
Issue Url: https://github.com/pharo-project/pharo/issues/fixing
Build Url: https://ci.inria.fr/pharo-ci-jenkins2/job/Test%20pending%20pull%20request%2…
Jan. 11, 2020
Re: [Pharo-dev] about signal
by ducasse
Yes this was really fun for me to discover that in newProcess
newProcess
"Answer a Process running the code in the receiver. The process is not
scheduled.
IMPORTANT! Debug stepping this deep infrastructure may lock your Image
If you are not sure what you are doing, close the debugger now."
<primitive: 19> "Simulation guard"
^Process
forContext:
[self value.
Processor terminateActive] asContext
priority: Processor activePriority
> On 11 Jan 2020, at 11:06, Ben Coman <btc(a)openinworld.com> wrote:
>
>
>
> On Sat, 11 Jan 2020 at 18:01, ducasse <stepharo(a)netcourrier.com <mailto:stepharo@netcourrier.com>> wrote:
>
>
>> On 11 Jan 2020, at 10:50, Ben Coman <btc(a)openinworld.com <mailto:btc@openinworld.com>> wrote:
>>
>>
>>
>> On Sat, 11 Jan 2020 at 06:31, Sven Van Caekenberghe <sven(a)stfx.eu <mailto:sven@stfx.eu>> wrote:
>> Hi Ben,
>>
>> Great approach, though I would make one change to make your example completely copy/paste runnable.
>>
>> Stef's original example:
>>
>> | trace semaphore p1 p2 |
>>
>> semaphore := Semaphore new.
>>
>> trace := [ :message |
>> ('[{1}] {2}' format: { Processor activeProcess priority. message }) crLog ].
>>
>> p1 := [
>> semaphore wait.
>> trace value: 'Process 1' ] fork.
>>
>> p2 := [
>> semaphore signal.
>> trace value: 'Process 2' ] fork.
>>
>> trace value: 'Original process pre-yield'.
>> Processor yield.
>> trace value: 'Original process post-yield'.
>>
>> Gives:
>>
>> '[40] Original process pre-yield'
>> '[40] Process 2'
>> '[40] Original process post-yield'
>> '[40] Process 1'
>>
>> But not running the yield section gives:
>>
>> '[40] Process 2'
>> '[40] Process 1'
>>
>> which is an identical result if the 'Original process' traces are filtered out.
>>
>>
>> From this it would seem that the code in p2 continues after signal and only later does p1 get past its wait.
>>
>> Yes, a #signal does not transfer execution unless the waiting-process that received the signal is a higher priority.
>> Within the same priority, it just makes waiting-process runnable, and the highest-priority-runnable-process is the one that is run.
>>
>>
>> Playing with the priorities we can change that order (apparently);
>>
>> | trace semaphore p1 p2 |
>>
>> semaphore := Semaphore new.
>>
>> trace := [ :message |
>> ('[{1}] {2}' format: { Processor activeProcess priority. message }) crLog ].
>>
>> p1 := [
>> semaphore wait.
>> trace value: 'Process 1' ] forkAt: 30.
>>
>> p2 := [
>> semaphore signal.
>> trace value: 'Process 2' ] forkAt: 20.
>>
>> Gives:
>>
>> '[30] Process 1'
>> '[20] Process 2'
>>
>> Again, the yield section makes no difference. So something else happened.
>>
>> The yield made no difference because it only facilitates other processes at-the-SAME-priority getting a chance to run.
>> Yield doesn't put the current-process to sleep, it just moves the process to the back of its-priority-runQueue. It gets to run again before any lower priority process gets a chance to run.
>>
>> Yielding will never allow a lower-priority-process to run.
>> For a lower-priority process to run, the current-process needs to sleep rather than yield.
>
> Indeed. I will add this note to my chapter.
>
>>
>> Compare...
>> | trace semaphore p1 p2 |
>> semaphore := Semaphore new.
>> trace := [ :message | ('@{1} {2}' format: { Processor activePriority. message }) crLog ].
>> p1 := [
>> trace value: 'Process 1a waits for signal on semaphore'.
>> semaphore wait.
>> trace value: 'Process 1b received signal' ] forkAt: 30.
>> p2 := [
>> trace value: 'Process 2a signals semaphore'.
>> semaphore signal.
>> trace value: 'Process 2b continues' ] forkAt: 20.
>> trace value: 'Original process pre-yield'.
>> Processor yield.
>> trace value: 'Original process post-yield'.
>>
>> ==>
>> '@40 Original process pre-yield'
>> '@40 Original process post-yield'
>> '@30 Process 1a waits for signal on semaphore'
>> '@20 Process 2a signals semaphore'
>> '@30 Process 1b received signal'
>> '@20 Process 2b continues'
>>
>> with...
>> | trace semaphore p1 p2 |
>> semaphore := Semaphore new.
>> trace := [ :message | ('@{1} {2}' format: { Processor activePriority. message }) crLog ].
>> p1 := [
>> trace value: 'Process 1a waits for signal on semaphore'.
>> semaphore wait.
>> trace value: 'Process 1b received signal' ] forkAt: 30.
>> p2 := [
>> trace value: 'Process 2a signals semaphore'.
>> semaphore signal.
>> trace value: 'Process 2b continues' ] forkAt: 20.
>> trace value: 'Original process pre-delay'.
>> 1 milliSecond wait.
>> trace value: 'Original process post-delay'.
>>
>> ==>
>> '@40 Original process pre-delay'
>> '@30 Process 1a waits for signal on semaphore'
>> '@20 Process 2a signals semaphore'
>> '@30 Process 1b received signal'
>> '@20 Process 2b continues'
>> '@40 Original process post-delay'
>>
>>
>>
>> Stef, on further consideration I think your first examples should not-have p1 and p2 the same priority.
>> Scheduling of same-priority processes and how they interact with the UI thread is an extra level of complexity that may be better done shortly after.
>
> Yes I realize it.
>> Not needing to trace "Original process" in the first example gives less for the reader to digest
>
> Yes I thought the same.
> I thought that I could have the following strategy.
> Give a first simple version, them revisiting it after.
>
> At first glance I thought using #fork would a simpler example than using #forkAt:,
> but the former interacts with the implicit priority of existing UI process, while the latter is explicit and so actually makes a simpler example.
>
> cheers -ben
Jan. 11, 2020
Re: [Pharo-dev] about signal
by Ben Coman
On Sat, 11 Jan 2020 at 18:01, ducasse <stepharo(a)netcourrier.com> wrote:
>
>
> On 11 Jan 2020, at 10:50, Ben Coman <btc(a)openinworld.com> wrote:
>
>
>
> On Sat, 11 Jan 2020 at 06:31, Sven Van Caekenberghe <sven(a)stfx.eu> wrote:
>
>> Hi Ben,
>>
>> Great approach, though I would make one change to make your example
>> completely copy/paste runnable.
>>
>> Stef's original example:
>>
>> | trace semaphore p1 p2 |
>>
>> semaphore := Semaphore new.
>>
>> trace := [ :message |
>> ('[{1}] {2}' format: { Processor activeProcess priority. message
>> }) crLog ].
>>
>> p1 := [
>> semaphore wait.
>> trace value: 'Process 1' ] fork.
>>
>> p2 := [
>> semaphore signal.
>> trace value: 'Process 2' ] fork.
>>
>> trace value: 'Original process pre-yield'.
>> Processor yield.
>> trace value: 'Original process post-yield'.
>>
>> Gives:
>>
>> '[40] Original process pre-yield'
>> '[40] Process 2'
>> '[40] Original process post-yield'
>> '[40] Process 1'
>>
>> But not running the yield section gives:
>
>
>> '[40] Process 2'
>> '[40] Process 1'
>>
>
> which is an identical result if the 'Original process' traces are filtered
> out.
>
>
>
>> From this it would seem that the code in p2 continues after signal and
>> only later does p1 get past its wait.
>>
>
> Yes, a #signal does not transfer execution unless the waiting-process that
> received the signal is a higher priority.
> Within the same priority, it just makes waiting-process runnable, and the
> highest-priority-runnable-process is the one that is run.
>
>
>
> Playing with the priorities we can change that order (apparently);
>>
>> | trace semaphore p1 p2 |
>>
>> semaphore := Semaphore new.
>>
>> trace := [ :message |
>> ('[{1}] {2}' format: { Processor activeProcess priority. message
>> }) crLog ].
>>
>> p1 := [
>> semaphore wait.
>> trace value: 'Process 1' ] forkAt: 30.
>>
>> p2 := [
>> semaphore signal.
>> trace value: 'Process 2' ] forkAt: 20.
>>
>> Gives:
>>
>> '[30] Process 1'
>> '[20] Process 2'
>>
>> Again, the yield section makes no difference. So something else happened.
>>
>
> The yield made no difference because it only facilitates other processes
> at-the-SAME-priority getting a chance to run.
> Yield doesn't put the current-process to sleep, it just moves the process
> to the back of its-priority-runQueue. It gets to run again before any lower
> priority process gets a chance to run.
>
> Yielding will never allow a lower-priority-process to run.
> For a lower-priority process to run, the current-process needs to sleep
> rather than yield.
>
>
> Indeed. I will add this note to my chapter.
>
>
> Compare...
> | trace semaphore p1 p2 |
> semaphore := Semaphore new.
> trace := [ :message | ('@{1} {2}' format: { Processor activePriority.
> message }) crLog ].
> p1 := [
> trace value: 'Process 1a waits for signal on semaphore'.
> semaphore wait.
> trace value: 'Process 1b received signal' ] forkAt: 30.
> p2 := [
> trace value: 'Process 2a signals semaphore'.
> semaphore signal.
> trace value: 'Process 2b continues' ] forkAt: 20.
> trace value: 'Original process pre-yield'.
> Processor yield.
> trace value: 'Original process post-yield'.
>
> ==>
> '@40 Original process pre-yield'
> '@40 Original process post-yield'
> '@30 Process 1a waits for signal on semaphore'
> '@20 Process 2a signals semaphore'
> '@30 Process 1b received signal'
> '@20 Process 2b continues'
>
> with...
> | trace semaphore p1 p2 |
> semaphore := Semaphore new.
> trace := [ :message | ('@{1} {2}' format: { Processor activePriority.
> message }) crLog ].
> p1 := [
> trace value: 'Process 1a waits for signal on semaphore'.
> semaphore wait.
> trace value: 'Process 1b received signal' ] forkAt: 30.
> p2 := [
> trace value: 'Process 2a signals semaphore'.
> semaphore signal.
> trace value: 'Process 2b continues' ] forkAt: 20.
> trace value: 'Original process pre-delay'.
> 1 milliSecond wait.
> trace value: 'Original process post-delay'.
>
> ==>
> '@40 Original process pre-delay'
> '@30 Process 1a waits for signal on semaphore'
> '@20 Process 2a signals semaphore'
> '@30 Process 1b received signal'
> '@20 Process 2b continues'
> '@40 Original process post-delay'
>
>
>
> Stef, on further consideration I think your first examples should not-have
> p1 and p2 the same priority.
> Scheduling of same-priority processes and how they interact with the UI
> thread is an extra level of complexity that may be better done shortly
> after.
>
>
> Yes I realize it.
>
> Not needing to trace "Original process" in the first example gives less
> for the reader to digest
>
>
> Yes I thought the same.
> I thought that I could have the following strategy.
> Give a first simple version, them revisiting it after.
>
At first glance I thought using #fork would a simpler example than using
#forkAt:,
but the former interacts with the implicit priority of existing UI process,
while the latter is explicit and so actually makes a simpler example.
cheers -ben
Jan. 11, 2020