On Sat, 11 Jan 2020 at 06:31, Sven Van Caekenberghe <[email protected]> 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.

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.
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

Reply via email to