<br><br><div class="gmail_quote">On Feb 5, 2008 10:04 AM, Andreas Raab &lt;<a href="mailto:andreas.raab@gmx.de">andreas.raab@gmx.de</a>&gt; 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&gt;&gt;startWorkerProcess<br>
 &nbsp; &nbsp; &nbsp; &nbsp;&quot;worker is an instance variable&quot;<br> &nbsp; &nbsp; &nbsp; &nbsp;worker:= [self runWorkerProcess] fork.<br><br>MyClass&gt;&gt;runWorkerProcess<br> &nbsp; &nbsp; &nbsp; &nbsp;&quot;Run the worker process&quot;<br> &nbsp; &nbsp; &nbsp; &nbsp;[Processor activeProcess == worker] whileTrue:[<br>
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&quot;...do the work...&quot;<br> &nbsp; &nbsp; &nbsp; &nbsp;].<br><br>MyClass&gt;&gt;stopWorkerProcess<br> &nbsp; &nbsp; &nbsp; &nbsp;&quot;Stop the worker process&quot;<br> &nbsp; &nbsp; &nbsp; &nbsp;worker := nil. &quot;let it terminate itself&quot;<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 &quot;worker&quot;<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&#39;<br>priority but when it&#39;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&gt;&gt;fork and<br>
BlockContext&gt;&gt;forkAt: to read, e.g.,<br><br>BlockContext&gt;&gt;fork<br> &nbsp; &quot;Create and schedule a Process running the code in the receiver.&quot;<br> &nbsp; ^self forkAt: Processor activePriority<br><br>BlockContext&gt;&gt;forkAt: priority<br>
 &nbsp; &quot;Create and schedule a Process running the code in the receiver<br> &nbsp; at the given priority. Answer the newly created process.&quot;<br> &nbsp; | forkedProcess helperProcess |<br> &nbsp; forkedProcess := self newProcess.<br>
 &nbsp; forkedProcess priority: priority.<br> &nbsp; priority = Processor activePriority ifTrue:[<br> &nbsp; &nbsp; helperProcess := [forkedProcess resume] newProcess.<br> &nbsp; &nbsp; helperProcess priority: priority-1.<br> &nbsp; &nbsp; helperProcess resume.<br>
 &nbsp; ] ifFalse:[<br> &nbsp; &nbsp; forkedProcess resume<br> &nbsp; ].<br> &nbsp; ^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&#39;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&gt;&gt;startWorkerProcess<br> &nbsp; &nbsp; &nbsp; &nbsp;&quot;keepRunning is an instance variable&quot;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; keepRunning := true.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot; Always run worker processes as a lower priority than the controller process. &quot;<br>
 &nbsp; &nbsp; &nbsp;&nbsp; [self runWorkerProcess] forkAt: ProcessScheduler somethingeratherPriority.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot; sorry; I don&#39;t have Squeak handy right now, but you get the idea. &quot;<br><br>MyClass&gt;&gt;runWorkerProcess<br> &nbsp; &nbsp; &nbsp; &nbsp;&quot;Run the worker process&quot;<br>
 &nbsp; &nbsp; &nbsp; &nbsp;[keepRunning] whileTrue: [<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&quot;...do the work...&quot;<br> &nbsp; &nbsp; &nbsp; &nbsp;].<br><br>MyClass&gt;&gt;stopWorkerProcess<br> &nbsp; &nbsp; &nbsp; &nbsp;&quot;Stop the worker process&quot;<br> &nbsp; &nbsp; &nbsp;&nbsp; keepRunning := false. &quot;let it terminate itself&quot;<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>