[squeak-dev] Re: finalizing processes?

Yoshiki Ohshima yoshiki at vpri.org
Thu Dec 1 18:09:47 UTC 2011


At Thu, 01 Dec 2011 09:43:13 +0100,
Andreas Raab wrote:
> 
> On 12/1/2011 0:32, Yoshiki Ohshima wrote:
> >    Hello,
> >
> > I have trouble terminating some processes I make.  More specifically,
> > I'm trying to terminate some processes when the their associated
> > "owner" object is garbage collected.  The problem seems that these
> > processes hold back pointers to my owner object via outerContext of
> > the closures so the owner object does not get garbage collected when
> > nobody else is pointing to it.
> >
> > Attached is my test case.  After filing in this to a trunk image,
> > evaluate:
> >
> > 	k := KEventStream new.
> > 	KEventStream beTimer: k with: 100.
> >
> > in a workspace.  You'll see a little counter going on the left edge of
> > screen.  What I want to do is to stop the counter by evaluating:
> >
> > 	k := nil. Smalltalk garbageCollect.
> >
> > but the processes hold onto the closure, which in turn holds onto the
> > context for executing #beTimer:with:, and that context holds onto 'k',
> > or 'anObject'.
> >
> > I thought that closure could just be detached from the outer context but
> > it is not the case here.  Why?
> 
> Just guessing: Is it possibly because you're using a shared variable 
> (sema) in #beTimer:with:? In order to reference the shared variable from 
> the process the outer scope needs to be retained. You'd have to pass the 
> variable into the process to avoid requiring the outer context for sema, 
> along the lines of:
> 
> 
> 	timerProcess := [:sema|
> 		[true] whileTrue: [(Delay forMilliseconds: interval) wait. sema signal]
> 	] newProcessWith: {semaphore}.
> 	timerProcess priority: Processor timingPriority.
> 	timerProcess resume.

  Ah, I did not know about newProcessWith, but this approach does not
seem to solve the problem.  (Before reading this, I tried something
along the line of:

	timerProcess := [
		mySema := sema.
		myInterval := interval.
		[true] whileTrue: [(Delay forMilliseconds: myInterval) wait. mySema signal]] forkAt: Processor timingPriority.

but this did not work either.  As far as I can tell, 'outerContext' link
survives so the context does not go away.)

Now, my solution is to pass "Array with: anObject" to beTimer:with:
instead of "anObject", and in beTimer:with:, I assign nil to the
slot.  So, the outer context remains but it only holds onto an Array
with nil, and a finalization does kicks in now.

Thanks!

-- Yoshiki

If anybody is interested in, the code looks like:

beTimer: anObjectContainer with: interval

	| dict sema timerProcess updateProcess updater target anObject |
	sema := Semaphore new.
	updater := #display:.
	anObject := anObjectContainer at: 1.
	anObjectContainer at: 1 put: nil.
	target := WeakArray with: anObject.
	timerProcess := [
		[true] whileTrue: [(Delay forMilliseconds: interval) wait. sema signal]] forkAt: Processor timingPriority.
	updateProcess := [
		[true] whileTrue: [sema wait. (target at: 1) ifNotNil: [:t | t perform: updater with: Time millisecondClockValue]]] forkAt: Processor timingPriority.
	anObject property: #sema put: sema.
	anObject property: #timerProcess put: timerProcess.
	anObject property: #updateProcess put: updateProcess.

	dict := IdentityDictionary new.
	dict at: #timerProcess put: timerProcess.
	dict at: #updateProcess put: updateProcess.
	anObject toFinalizeSend: #finalize: to: self with: dict.
	^ anObject.



More information about the Squeak-dev mailing list