Hi Max,

On Fri, Feb 12, 2016 at 6:59 AM, Max Leske <maxleske@gmail.com> wrote:

Hi all,

I have a proposal and I���d like to hear your opinion.

Right now, when I want to wait for a process to finish I use something like #forkAndWait or I write a block with semaphores myself. This works fine for processes that I spawn and then immediately want to wait for. But what if I spawn a process somewhere else and only later know that I want to wait for its termination? Currently I would construct a polling loop to do that.

Here���s a different idea (which I���ve tested):

1. add instance variable ���terminationSemaphore��� to Process
2. at the end of Process>>terminate #ensure: that all waiting processes are signaled
3. add #waitForTermination message to Process:

waitForTermination
�� �� �� �� terminationSemaphore ifNil: [ terminationSemaphore := Semaphore new ].
�� �� �� �� self resume.
�� �� �� �� terminationSemaphore wait



This enables code like the following:

result := 0.
p := [ result := 2. 2 seconds asDelay wait ] newProcess
�� �� �� �� priority: 20;
�� �� �� �� yourself.

���don���t run the new process yet"
[ p waitForTermination. result2 := 3. ] forkAt: 30.
���p is now running, the second process is waiting"

p waitForTermination.
���p is still running, two processes are waiting���

���because processes waiting on a semaphore are signaled in the order
they sent #wait we even achieve ordering (at least with equal process
priorities) and so ���result2��� is not nil but 3���

{result. result2} ���#(2 3)


I wrote this in 10 minutes, so there���s room for polishing. I just want to know if this is something other people might want and if there are potential problems with process termination and semaphores which I am not aware of.

Seems very nice.�� But why not add both terminationSemaphore and result?�� So we have

Process class methods for instance creation
forBlock: aBlockClosure priority: anInteger��
"Answer an instance of me that has suspended aContext at priority anInteger."

<primitive: 19> "Simulation guard"
| newProcess |
(newProcess := self new)
suspendedContext:
[newProcess result: aBlockClosure value.
��newProcess terminationSemaphore ifNotNil: [:ts| ts signal].
"Since control is now at the bottom there is no need to terminate (which
runs unwinds) since all unwinds have been run.�� Simply suspend.
Note that we must use this form rather than e.g. Processor suspendActive
so that isTerminated answers true. ��isTerminated requires that if there is a
suspended context it is the bottom-most, but using a send would result in
the process's suspendedContext /not/ being the bottom-most."
newProcess suspend] asContext;
priority: anInteger.
^newProcess

BlockClosure methods for scheduling
newProcess
"Answer a Process running the code in the receiver. The process is not scheduled."
^Process forBlock: self priority: Processor activePriority

Process methods for termination
waitForTermination
terminationSemaphore ifNil: [ terminationSemaphore := Semaphore new ].
self resume.
terminationSemaphore wait.
^result

and hence

((1 to: 3) collect: [:i| [(Delay forSeconds: i) wait. i] forkAt: Processor activePriority - 1]) collect: [:p| p waitForTermination] #(1 2 3)


[find attached, leaving BlockClosure>>newProcessWith: as an exercise for the reader ;-) ]

_,,,^..^,,,_
best,��Eliot