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 <b...@openinworld.com> wrote:
> 
> 
> 
> On Sat, 11 Jan 2020 at 18:01, ducasse <steph...@netcourrier.com 
> <mailto:steph...@netcourrier.com>> wrote:
> 
> 
>> On 11 Jan 2020, at 10:50, Ben Coman <b...@openinworld.com 
>> <mailto:b...@openinworld.com>> wrote:
>> 
>> 
>> 
>> On Sat, 11 Jan 2020 at 06:31, Sven Van Caekenberghe <s...@stfx.eu 
>> <mailto:s...@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

Reply via email to