On 12 Feb 2016, at 19:35, Eliot Miranda <eliot.miranda@gmail.com> wrote:Hi Max,<waitForTermination.st>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 haveProcess class methods for instance creationforBlock: 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 (whichruns unwinds) since all unwinds have been run. Simply suspend.Note that we must use this form rather than e.g. Processor suspendActiveso that isTerminated answers true. isTerminated requires that if there is asuspended context it is the bottom-most, but using a send would result inthe process's suspendedContext /not/ being the bottom-most."newProcess suspend] asContext;priority: anInteger.^newProcessBlockClosure methods for schedulingnewProcess"Answer a Process running the code in the receiver. The process is not scheduled."^Process forBlock: self priority: Processor activePriorityProcess methods for terminationwaitForTermination
terminationSemaphore ifNil: [ terminationSemaphore := Semaphore new ].
self resume.
terminationSemaphore wait.^resultand 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