On Tue, May 10, 2016 at 6:31 PM, Vince Refiti <vin...@gmail.com> wrote: > Hello > > I am playing around with Semaphore, and wrote the following: > > | coll count sem | > coll := Array withAll: (1 to: 100). > count := 0. > sem := Semaphore new. > coll do: [ :each | > count := count + 1. > (count >= 5) > ifTrue: [ > Transcript show: 'waiting...'; cr. > sem wait ]. > > [ [ 2 seconds asDelay wait. > Transcript show: each printString, ' ', count printString; cr ] > ensure: [ > count := count -1. > sem signal ] ] fork ] > > The output is:
[snipped] > I was expecting 'waiting...' to alternate with the 'each-count' lines. Also > the entire statement paused for 2 seconds, spat out some lines, then waited > a little longer, and then finished. > > Can someone please explain this pattern? > > Thanks, Vince Hi Vince, General things to be aware of... * Transcript is not perturbing your result. * Playground code is executed in the context of the main UI-process. Thus... * An infinite loop will lock the UI. * A sem wait will lock the UI. * Processes at the same priority are scheduled cooperatively. * Processes at different priority are pre-emptively scheduled. I refactored your example to better highlight program flow... | coll count sem | Transcript clear. coll := Array withAll: (1 to: 99). count := 0. sem := Semaphore new. coll do: [ :each | count := count + 1. Transcript crShow: each printString; tab; tab; show: count printString, '+'. (count >= 5) ifTrue: [ sem isSignaled ifTrue: [ Transcript tab; show: ' nowait'. sem wait ] ifFalse: [ Transcript tab; show: ' wait'. sem wait. Transcript crShow: each printString; tab; tab; show: count printString; tab; show: ' postwait, excessSignals ' , sem excessSignals printString. ] ]. [ Transcript crShow: ' ', each printString; tab; tab; show: count printString; tab; show: ' delay'. 2 seconds asDelay wait. count := count -1. Transcript crShow: ' ', each printString; tab ; tab; show: count printString, '-'; tab; show: ' signal'. sem signal. ] fork. ] You will need to add... Semaphore>>excessSignals ^excessSignals For counts 1, 2, 3 & 4, forked processes -1 to -4 are queued to run, but don't run until the UI-process suspended by the wait at each=5, count=5, which is why the "waiting..." tag appears first. When the UI-process waits, processes -1 to -4 run in turn and immediately delay for two seconds. After this, they queued to run. Process-1 signals the UI-process to be queued to run. But processes -2 to -4 run first, signalling sem an extra three times. When the UI-process resumes, each=5, count=1 and sem has three excessSignals. Completing the do: adds process -5 to the run queue. Then counts 2, 3, & 4 queues processes -6, -7 & -8 to run. Counts 5, 6 & 7 consume the excessSignals without suspending, queing processes -9, -10 & -11 to run. At count=8, the UI-process suspends at the wait, and process -5 runs. This signals the UI-process to be queued to run. Processes -6 to -11 run, signalling sem an extra six times. When the UI-process resumes, each=12, count=1 and sem has six excessSignals. Completing the do: adds process -12 to the run queue. Then counts 2, 3, & 4 queues processes -13, -14 & -15 to run. Counts 5, 6, 7, 8, 9, 10 consume the excessSignals without suspending, queing processes -16, -17, -18, -19, -20, -21 to run. At count=11, the UI-process suspends at the wait, and process -12 runs. This signals the UI-process to be queued to run. Processes -13 to -21 run, signalling sem an extra nine times. ecetera... btw, The delay doesn't make much difference to how the forked processes interact with the main UI-process, since all forked processes execute before the UI-process resumed. It just interleaves the delay/signal tags rather than grouping them. 1 1+ 2 2+ 3 3+ 4 4+ 5 5+ wait 1 5 delay 2 5 delay 3 5 delay 4 5 delay 1 4- signal 2 3- signal 3 2- signal 4 1- signal 5 1 postwait, excessSignals 3 6 2+ 7 3+ 8 4+ 9 5+ nowait 10 6+ nowait 11 7+ nowait 12 8+ wait 5 8 delay 6 8 delay 7 8 delay 8 8 delay 9 8 delay 10 8 delay 11 8 delay 5 7- signal 6 6- signal 7 5- signal 8 4- signal 9 3- signal 10 2- signal 11 1- signal 12 1 postwait, excessSignals 6 13 2+ 14 3+ 15 4+ 16 5+ nowait 17 6+ nowait 18 7+ nowait 19 8+ nowait 20 9+ nowait 21 10+ nowait 22 11+ wait 12 11 delay 13 11 delay 14 11 delay 15 11 delay 16 11 delay 17 11 delay 18 11 delay 19 11 delay 20 11 delay 21 11 delay 12 10- signal 13 9- signal 14 8- signal 15 7- signal 16 6- signal 17 5- signal 18 4- signal 19 3- signal 20 2- signal 21 1- signal 22 1 postwait, excessSignals 9 23 2+ 24 3+ 25 4+ 26 5+ nowait 27 6+ nowait 28 7+ nowait 29 8+ nowait 30 9+ nowait 31 10+ nowait 32 11+ nowait 33 12+ nowait 34 13+ nowait 35 14+ wait 22 14 delay 23 14 delay 24 14 delay 25 14 delay 26 14 delay 27 14 delay 28 14 delay 29 14 delay 30 14 delay 31 14 delay 32 14 delay 33 14 delay 34 14 delay 22 13- signal 23 12- signal 24 11- signal 25 10- signal 26 9- signal 27 8- signal 28 7- signal 29 6- signal 30 5- signal 31 4- signal 32 3- signal 33 2- signal 34 1- signal 35 1 postwait, excessSignals 12 36 2+ 37 3+ 38 4+ 39 5+ nowait 40 6+ nowait 41 7+ nowait 42 8+ nowait 43 9+ nowait 44 10+ nowait 45 11+ nowait 46 12+ nowait 47 13+ nowait 48 14+ nowait 49 15+ nowait 50 16+ nowait 51 17+ wait 35 17 delay 36 17 delay 37 17 delay 38 17 delay 39 17 delay 40 17 delay 41 17 delay 42 17 delay 43 17 delay 44 17 delay 45 17 delay 46 17 delay 47 17 delay 48 17 delay 49 17 delay 50 17 delay 35 16- signal 36 15- signal 37 14- signal 38 13- signal 39 12- signal 40 11- signal 41 10- signal 42 9- signal 43 8- signal 44 7- signal 45 6- signal 46 5- signal 47 4- signal 48 3- signal 49 2- signal 50 1- signal 51 1 postwait, excessSignals 15 52 2+ 53 3+ 54 4+ 55 5+ nowait 56 6+ nowait 57 7+ nowait 58 8+ nowait 59 9+ nowait 60 10+ nowait 61 11+ nowait 62 12+ nowait 63 13+ nowait 64 14+ nowait 65 15+ nowait 66 16+ nowait 67 17+ nowait 68 18+ nowait 69 19+ nowait 70 20+ wait 51 20 delay 52 20 delay 53 20 delay 54 20 delay 55 20 delay 56 20 delay 57 20 delay 58 20 delay 59 20 delay 60 20 delay 61 20 delay 62 20 delay 63 20 delay 64 20 delay 65 20 delay 66 20 delay 67 20 delay 68 20 delay 69 20 delay 51 19- signal 52 18- signal 53 17- signal 54 16- signal 55 15- signal 56 14- signal 57 13- signal 58 12- signal 59 11- signal 60 10- signal 61 9- signal 62 8- signal 63 7- signal 64 6- signal 65 5- signal 66 4- signal 67 3- signal 68 2- signal 69 1- signal 70 1 postwait, excessSignals 18 71 2+ 72 3+ 73 4+ 74 5+ nowait 75 6+ nowait 76 7+ nowait 77 8+ nowait 78 9+ nowait 79 10+ nowait 80 11+ nowait 81 12+ nowait 82 13+ nowait 83 14+ nowait 84 15+ nowait 85 16+ nowait 86 17+ nowait 87 18+ nowait 88 19+ nowait 89 20+ nowait 90 21+ nowait 91 22+ nowait 92 23+ wait 70 23 delay 71 23 delay 72 23 delay 73 23 delay 74 23 delay 75 23 delay 76 23 delay 77 23 delay 78 23 delay 79 23 delay 80 23 delay 81 23 delay 82 23 delay 83 23 delay 84 23 delay 85 23 delay 86 23 delay 87 23 delay 88 23 delay 89 23 delay 90 23 delay 91 23 delay 70 22- signal 71 21- signal 72 20- signal 73 19- signal 74 18- signal 75 17- signal 76 16- signal 77 15- signal 78 14- signal 79 13- signal 80 12- signal 81 11- signal 82 10- signal 83 9- signal 84 8- signal 85 7- signal 86 6- signal 87 5- signal 88 4- signal 89 3- signal 90 2- signal 91 1- signal 92 1 postwait, excessSignals 21 93 2+ 94 3+ 95 4+ 96 5+ nowait 97 6+ nowait 98 7+ nowait 99 8+ nowait 92 8 delay 93 8 delay 94 8 delay 95 8 delay 96 8 delay 97 8 delay 98 8 delay 99 8 delay 92 7- signal 93 6- signal 94 5- signal 95 4- signal 96 3- signal 97 2- signal 98 1- signal 99 0- signal