#fork and deterministic resumption of the resulting process

Louis LaBrunda Lou at Keystone-Software.com
Tue Feb 5 20:47:19 UTC 2008


Hi,

I ran into a similar problem in VAST that I got around by extending Block and
Process.  I extended Block with #forkReady, #forkReadyAt: and some others and
Process with #ready.  The #forkReady extension to Block basically does what it
says, it creates a new fork or process in the ready state by does not start it
immediately.  The new process will wait for its normal turn to start.  The
#ready extension to Process makes the process ready without running it
immediately and is used by #forkReady.

I didn't want to change the way #fork worked so I made the extensions, but I
don't see any reason why #fork couldn't be changed to work the way I made
#forkReady work.  I would be surprised if anyone was counting on #fork
immediately starting the new process before the process that creates the fork
would yield for other reasons.

Lou

On Mon, 04 Feb 2008 13:04:13 -0800, 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?
>
>Cheers,
>   - Andreas
>
-----------------------------------------------------------
Louis LaBrunda
Keystone Software Corp.
SkypeMe callto://PhotonDemon
mailto:Lou at Keystone-Software.com http://www.Keystone-Software.com




More information about the Squeak-dev mailing list