On 23 April 2013 21:07, Luc Fabresse <[hidden email]> wrote:
> Hi all, > > > @Sven, yes of course I forgot the WeakArray to save the hard ref in my > previous explanation. > > > 2013/4/23 Igor Stasenko <[hidden email]> >> >> On 23 April 2013 18:02, Sean P. DeNigris <[hidden email]> wrote: >> > Igor Stasenko wrote >> >> but what you expecting? >> >> you refer to 'self' multiple times. sure thing it cannot be GC-ed, >> >> neither process will die because >> >> of plenty of references on stack. >> >> Even block closure which you creating for fork will have home context >> >> which keeps reference to 'self', >> >> e.g. receiver. >> > >> > I'm expecting magic apparently because I am stupid when it comes to >> > processes ;) I changed all the "self"s to array first, which also didn't >> > work, but then I read your statement about the home context... >> > >> > Luc's class-side trick seems to work: >> > Timer>>start >> > >> > | array | >> > array := WeakArray with: self. >> > process := self class createProcessFor: array. "tried passing >> > self here, >> > but it seemed to keep the process around" >> > >> of course, because the home context (will be the method below) of >> closure captures method's arguments, >> and holding them strongly.. >> >> >> > Timer class>>createProcessFor: aWeakArray >> > >> > [ [ aWeakArray first notNil ] whileTrue: [ >> > | timer | >> > aWeakArray first interval asDelay wait. >> > "We have to check again if the timer was garbage >> > collected during the >> > wait" >> > aWeakArray first ifNotNil: [ >> > aWeakArray first value: aWeakArray first value + >> > 1. >> > aWeakArray first announcer announce: >> > (TimerValueChanged to: aWeakArray >> > first value) ] ] ] fork. >> > >> > Wow, it would seem that an object using a process internally that is >> > only >> > valid when the object is around is a fairly common use case. I can't >> > believe >> > how complicated this is :/ >> > >> it is not apparent to me why this is common use case. :) >> >> you can also simply pass a copy of 'self' to process. >> as long as copy accessing same announcer, your ticker process will >> work perfectly. >> then all you would need to do is: >> >> | copy | >> copy := self copy. > > > @Igor. > It will not work here I think. > because you make the shallow copy before initializing the process and the > finalize message is then sent to the copy. this is exactly what i intended. The original don't needs to even know the process. It simply passing the initialized values (interval, announcer etc to its copy).. the rest is done by copy. Like that there is guarantee that you won't leak reference of original object to worker thread. > as Sven proposed, a WeakArray would be good but I never deeply test it. > You can do it with weak array as well. To make code less uglier, capture the object into temp for a while, like that you don't have to do 'array first ifnotnil:' all the time, e.g.: temp := array first. temp ifNotNil: [ blah blah "here you have guarantee that anything which stored in 'array first' will not be GCed" ]. temp := nil. > Anyway, I always fight with the finalization mechanism. > > With Noury we wrote an ActiveObject class some time ago that has an internal > process that is stopped and the activeobject is finalized. > The only thing is to be **really** carreful when giving the block to the > ActiveObject to not introduce references. > > Here one of the test case that is green: > > testDoesStopBlockUponFinalizationForLowestPriority > |counter startSemaphore finalizationSemaphore process | > counter := 0. > startSemaphore := Semaphore new. > finalizationSemaphore := Semaphore new. > activeObject := ActiveObject > do: [ > startSemaphore signal. > [(Delay forMilliseconds: 50) wait]repeat > ] > ensure: [ > counter := 1. > finalizationSemaphore signal. > ]. > activeObject > priority: Processor lowestPriority; > start. > self deny: (startSemaphore waitTimeoutSeconds: 2). > process := activeObject process. > activeObject := nil. > Smalltalk garbageCollect. > self deny: (finalizationSemaphore waitTimeoutSeconds: 2). > self assert: counter = 1. > self assert: process isTerminated > > > Here the whole code: > > MCHttpRepository > location: 'http://car.mines-douai.fr/squeaksource/ReusableBricks' > user: '' > password: '' > > Luc > > >> >> process := self class createProcessFor: copy. >> WeakRegistry default add: self executor: copy. >> >> and implement: >> >> finalize >> process terminate. >> process := nil. >> >> >> Then createProcessFor: will be simple: >> >> Timer class>>createProcessFor: timer >> [ >> [ timer wait. " make Demeter a bit happier" >> timer tick. "this should increment counter and announce >> TimerValueChanged, >> like that we're not make Demeter unhappy" >> ] whileTrue ] fork. >> >> (actually , to make mr.Demeter completely happy, i would do >> [ timer waitAndTick ] whileTrue. >> ) >> >> and, tick, will be something like that: >> >> tick >> process ifNil: [ ^ false ]. >> self incrementCounter. >> self announce: (MyGreatAnnouncement with: whatever). >> ^ true. >> >> cheerz :) >> >> > ----- >> > Cheers, >> > Sean >> > -- >> > View this message in context: >> > http://forum.world.st/Terminating-a-Process-when-an-object-dies-tp4683036p4683144.html >> > Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com. >> > >> >> >> >> -- >> Best regards, >> Igor Stasenko. >> > -- Best regards, Igor Stasenko. |
In reply to this post by Sean P. DeNigris
On 23 April 2013 23:19, Sean P. DeNigris <[hidden email]> wrote:
> Igor Stasenko wrote >> well, #createProcessFor: implies that copy get's the pointer to process. >> no need to pass it back to sender. > > I need the return value because I need to suspend and resume the process > from the original Timer, which is what the GUI holds a pointer to. > ah ok. well, you see, you have too many concerns combined at single point. so, why then it surprises you that code is so ugly? :) ... and btw, with such additional concern i fear that you will become a victim of another pitfall: - suspending process which waits on semaphore (delay) may be resumed without your permission by signaling that semaphore (when delay expires). and the problem is a design flaw in Semaphore/Process implementation which treats a process which waits on semaphore as 'suspended'. You can look for mailing list archive for discussion about that (if i remember, i raised this issue first in squeak mailing list). > > > ----- > Cheers, > Sean > -- > View this message in context: http://forum.world.st/Terminating-a-Process-when-an-object-dies-tp4683036p4683198.html > Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com. > -- Best regards, Igor Stasenko. |
In reply to this post by Sven Van Caekenberghe-2
On 23 Apr 2013, at 22:00, Sven Van Caekenberghe <[hidden email]> wrote: > On 23 Apr 2013, at 19:59, "Sean P. DeNigris" <[hidden email]> wrote: > >> Sean P. DeNigris wrote >>> If you run TimerTest>>#testStart from Nautilus with an open Process >>> Browser (with auto-update enabled), you'll see the process appear and then >>> disappear. >> >> Although if I evaluate the snippet in the class comment of SpdLedMorph, the >> process hangs around. Arggghhhh. This is crazy!!! > > I loaded your code and I have the impression that it works, both in the test and in a workspace. > But it drives me crazy that my version does not seem to work. > I will have to come back to this tomorrow with a fresh mind. > > Sven I figured out what went wrong ! Two things: - you cannot delegate the waiting on the delay to the timer instance even though that is more elegant: the problem is that then the timer instance will be on the stack during the wait, which is a strong reference, hence the timer does not become garbage (unless you happen to intervene in-between 2 waits ;-) - you cannot call #start from an inspector, that seems to create a reference from a NOCController to the inspector instance and to the timer which is being inspected; this reference remains when the inspector closes, this is again a strong reference, hence the timer does not become garbage I am not sure, but the 2nd point feels like a (potentially serious) bug… Sven -- Sven Van Caekenberghe http://stfx.eu Smalltalk is the Red Pill |
Free forum by Nabble | Edit this page |