#fork and deterministic resumption of the resulting process
Michael van der Gulik
mikevdg at gmail.com
Mon Feb 4 22:00:32 UTC 2008
On Feb 5, 2008 10:04 AM, Andreas Raab <andreas.raab at gmx.de> wrote:
> Hi -
>
> In my never-ending quest for questionable behavior in multi-threaded
> situations just today I ran into a pattern which is dangerously common
> in our code. It basically goes like this:
>
> MyClass>>startWorkerProcess
> "worker is an instance variable"
> worker:= [self runWorkerProcess] fork.
>
> MyClass>>runWorkerProcess
> "Run the worker process"
> [Processor activeProcess == worker] whileTrue:[
> "...do the work..."
> ].
>
> MyClass>>stopWorkerProcess
> "Stop the worker process"
> worker := nil. "let it terminate itself"
>
> Those of you who can immediately tell what the problem is should get a
> medal for an outstanding knack of analyzing concurrency problems ;-)
>
> For the rest of us, the problem is that #fork in the above is not
> deterministic in the way that there is no guarantee whether the "worker"
> variable will be assigned when we enter the worker loop. It *would* be
> deterministic if the priority were below or above the current process'
> priority but when it's the same it can be affected by environmental
> effects (external signals, delay processing etc) leading to some very
> obscure runtime problems (in the above, the process would just not start).
>
> To fix this problem I have changed BlockContext>>fork and
> BlockContext>>forkAt: to read, e.g.,
>
> BlockContext>>fork
> "Create and schedule a Process running the code in the receiver."
> ^self forkAt: Processor activePriority
>
> BlockContext>>forkAt: priority
> "Create and schedule a Process running the code in the receiver
> at the given priority. Answer the newly created process."
> | forkedProcess helperProcess |
> forkedProcess := self newProcess.
> forkedProcess priority: priority.
> priority = Processor activePriority ifTrue:[
> helperProcess := [forkedProcess resume] newProcess.
> helperProcess priority: priority-1.
> helperProcess resume.
> ] ifFalse:[
> forkedProcess resume
> ].
> ^forkedProcess
>
> This will make sure that #fork has (for the purpose of resumption) the
> same semantics as forking at a lower priority has.
>
> What do people think about this?
>
I'm thinking that the above is an ugly hack. When we eventually write an
interpreter which is truly multitasking, your original bug will re-appear.
What you wanted to do, rather than redefining the Process class, is:
MyClass>>startWorkerProcess
"keepRunning is an instance variable"
keepRunning := true.
" Always run worker processes as a lower priority than the controller
process. "
[self runWorkerProcess] forkAt: ProcessScheduler
somethingeratherPriority.
" sorry; I don't have Squeak handy right now, but you get the idea. "
MyClass>>runWorkerProcess
"Run the worker process"
[keepRunning] whileTrue: [
"...do the work..."
].
MyClass>>stopWorkerProcess
"Stop the worker process"
keepRunning := false. "let it terminate itself"
Or better, make an abstraction:
process := WorkerTask doing: [ someObject doSomeWork ].
process start.
process stop.
Gulik.
--
http://people.squeakfoundation.org/person/mikevdg
http://gulik.pbwiki.com/
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20080205/a84d518e/attachment.htm
More information about the Squeak-dev
mailing list
|