<br><br><div class="gmail_quote">On Feb 5, 2008 10:04 AM, Andreas Raab <<a href="mailto:andreas.raab@gmx.de">andreas.raab@gmx.de</a>> wrote:<br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
Hi -<br><br>In my never-ending quest for questionable behavior in multi-threaded<br>situations just today I ran into a pattern which is dangerously common<br>in our code. It basically goes like this:<br><br>MyClass>>startWorkerProcess<br>
"worker is an instance variable"<br> worker:= [self runWorkerProcess] fork.<br><br>MyClass>>runWorkerProcess<br> "Run the worker process"<br> [Processor activeProcess == worker] whileTrue:[<br>
"...do the work..."<br> ].<br><br>MyClass>>stopWorkerProcess<br> "Stop the worker process"<br> worker := nil. "let it terminate itself"<br><br>Those of you who can immediately tell what the problem is should get a<br>
medal for an outstanding knack of analyzing concurrency problems ;-)<br><br>For the rest of us, the problem is that #fork in the above is not<br>deterministic in the way that there is no guarantee whether the "worker"<br>
variable will be assigned when we enter the worker loop. It *would* be<br>deterministic if the priority were below or above the current process'<br>priority but when it's the same it can be affected by environmental<br>
effects (external signals, delay processing etc) leading to some very<br>obscure runtime problems (in the above, the process would just not start).<br><br>To fix this problem I have changed BlockContext>>fork and<br>
BlockContext>>forkAt: to read, e.g.,<br><br>BlockContext>>fork<br> "Create and schedule a Process running the code in the receiver."<br> ^self forkAt: Processor activePriority<br><br>BlockContext>>forkAt: priority<br>
"Create and schedule a Process running the code in the receiver<br> at the given priority. Answer the newly created process."<br> | forkedProcess helperProcess |<br> forkedProcess := self newProcess.<br>
forkedProcess priority: priority.<br> priority = Processor activePriority ifTrue:[<br> helperProcess := [forkedProcess resume] newProcess.<br> helperProcess priority: priority-1.<br> helperProcess resume.<br>
] ifFalse:[<br> forkedProcess resume<br> ].<br> ^forkedProcess<br><br>This will make sure that #fork has (for the purpose of resumption) the<br>same semantics as forking at a lower priority has.<br><br>What do people think about this?<br>
<font color="#888888"></font></blockquote><div><br><br>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.<br><br>What you wanted to do, rather than redefining the Process class, is:<br>
<br>MyClass>>startWorkerProcess<br> "keepRunning is an instance variable"<br> keepRunning := true.<br> " Always run worker processes as a lower priority than the controller process. "<br>
[self runWorkerProcess] forkAt: ProcessScheduler somethingeratherPriority.<br> " sorry; I don't have Squeak handy right now, but you get the idea. "<br><br>MyClass>>runWorkerProcess<br> "Run the worker process"<br>
[keepRunning] whileTrue: [<br> "...do the work..."<br> ].<br><br>MyClass>>stopWorkerProcess<br> "Stop the worker process"<br> keepRunning := false. "let it terminate itself"<br>
<br>Or better, make an abstraction:<br><br> process := WorkerTask doing: [ someObject doSomeWork ].<br>process start.<br>process stop.<br><br>Gulik.<br><br><br><br><br></div></div><br><br clear="all"><br>-- <br><a href="http://people.squeakfoundation.org/person/mikevdg">http://people.squeakfoundation.org/person/mikevdg</a><br>
<a href="http://gulik.pbwiki.com/">http://gulik.pbwiki.com/</a>