Hi Ben, > On 11 Jan 2020, at 10:50, Ben Coman <b...@openinworld.com> wrote: > > > > On Sat, 11 Jan 2020 at 06:31, Sven Van Caekenberghe <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.
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