#fork and deterministic resumption of the resulting process

Terry Raymond squeak-craft at cox.net
Mon Feb 4 22:36:05 UTC 2008


Being aware of the problem Andreas illustrated, I frequently
write;

workerProcess := [self runWorkerProcess] newProcess.
workerProcess resume.

I think changing the semantics of fork is a way to introduce
a bug to existing code, i.e. one that is aware of the way
fork works and relies on it to work that way.

However, being that its operation is not too obvious you
could always write another method, maybe #forkDeferred, to
accomplish what Andreas is proprosing.

Terry
 
===========================================================
Terry Raymond
Crafted Smalltalk
80 Lazywood Ln.
Tiverton, RI  02878
(401) 624-4517      traymond at craftedsmalltalk.com
<http://www.craftedsmalltalk.com>
===========================================================
> -----Original Message-----
> From: squeak-dev-bounces at lists.squeakfoundation.org [mailto:squeak-dev-
> bounces at lists.squeakfoundation.org] On Behalf Of Andreas Raab
> Sent: Monday, February 04, 2008 4:04 PM
> To: The general-purpose Squeak developers list
> Subject: #fork and deterministic resumption of the resulting process
> 
> 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?
> 
> Cheers,
>    - Andreas




More information about the Squeak-dev mailing list