[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
|