All, I just stumbled over something which thought was pretty easy - turned out it isn't as easy as I thought or I'm simply _______ (fill in expression of choice like "too dumb", "blind", etc.) I have an object which starts a background process to do it's job. This object holds a reference to the running proccess in an instance variable. My goal is to #terminate that proccess once the object isn't needed anymore (before GC). Using WeakRegistry for the object itself doesn't work. E.g. MyObject>>#initialize super initialize. WeakRegistry default register: self. myProcess := self startProcess. MyObject>>#finalize myProcess terminate. "Doesn't work. myProcess is already nil" I think this is due to all the ivars of the object already being nil when #finalize is begin called. As far as I read the code this is due to Object>>#executor returning a shallow copy of the object and thus being by intention ... So how to proceed? Did I miss something obvious? Is overwriting #executor the way to go (in terms of "does it work" and "doesn't it break something")? Best Regards, Udo
Udo Schneider wrote:
All,
I just stumbled over something which thought was pretty easy - turned out it isn't as easy as I thought or I'm simply _______ (fill in expression of choice like "too dumb", "blind", etc.)
I have an object which starts a background process to do it's job. This object holds a reference to the running proccess in an instance variable.
My goal is to #terminate that proccess once the object isn't needed anymore (before GC).
Using WeakRegistry for the object itself doesn't work. E.g.
MyObject>>#initialize super initialize. WeakRegistry default register: self. myProcess := self startProcess.
MyObject>>#finalize myProcess terminate. "Doesn't work. myProcess is already nil"
I think this is due to all the ivars of the object already being nil when #finalize is begin called. As far as I read the code this is due to Object>>#executor returning a shallow copy of the object and thus being by intention ...
So how to proceed? Did I miss something obvious? Is overwriting #executor the way to go (in terms of "does it work" and "doesn't it break something")?
Best Regards,
Udo
I don't know much about finalization of Weak constructs, but maybe an alternative. I assume you have something like.. startProcess [ "do stuff" ] fork. so how about... startProcess [ [ "do stuff" myProcess = nil. ] whileFalse ] fork. cheers -ben
On 02.08.2014 15:33, Ben Coman wrote:
I don't know much about finalization of Weak constructs, but maybe an alternative. I assume you have something like.. startProcess [ "do stuff" ] fork.
so how about... startProcess [ [ "do stuff" myProcess = nil. ] whileFalse ] fork.
cheers -ben
That's a clever way to do it ... only it doesn't work :-( My current understanding is that "self" in the block refers to the original instance where "myProcess" is still assigned. "self" in #finalize is the "executor" object which is (by default) a #shallowCopy of the object where ivar are nil. I currently have the feeling I'm missing something. Finalization shouldn't be that hard ... or may I'm simply spoiled comming from a Dolphin Smalltalk background :-) Thanks for your help, Udo
We should write a chapter on finalization but since I do not know it well (and I forget)... igor will answer you. Stef On 2/8/14 13:16, Udo Schneider wrote:
All,
I just stumbled over something which thought was pretty easy - turned out it isn't as easy as I thought or I'm simply _______ (fill in expression of choice like "too dumb", "blind", etc.)
I have an object which starts a background process to do it's job. This object holds a reference to the running proccess in an instance variable.
My goal is to #terminate that proccess once the object isn't needed anymore (before GC).
Using WeakRegistry for the object itself doesn't work. E.g.
MyObject>>#initialize super initialize. WeakRegistry default register: self. myProcess := self startProcess.
MyObject>>#finalize myProcess terminate. "Doesn't work. myProcess is already nil"
I think this is due to all the ivars of the object already being nil when #finalize is begin called. As far as I read the code this is due to Object>>#executor returning a shallow copy of the object and thus being by intention ...
So how to proceed? Did I miss something obvious? Is overwriting #executor the way to go (in terms of "does it work" and "doesn't it break something")?
Best Regards,
Udo
On 04.08.2014 21:35, stepharo wrote:> We should write a chapter on finalization but since I do not know it
well (and I forget)... igor will answer you.
Stef
I found "the" bug. It seems it's a side effect of finalization, WeakRegistry and cyclic references. I'll write a TestCase for that. Thanks, Udo
TaskIT has a feature named StickyReference, for that propouse, is not trivial at all, because when you fork you are using a block that has a reference to a context. In the end even if your variable is nil, your process is being pointed by the context. What i did in TaskIT is to have a witness object, that mixed with a ghost proxy (the one you will be pointing) can do the magic. If what you want in your process variable is not really a reference to the process or if you have enough with a partial proxy based in DNU, things can go easier, you just need to register that third object into the weak resgistry. If you check out taskit commit 20 you will find a mechanism based in a DNU based proxy. If you checkout the last stable version you will find the witness/ghost proxy based one. In any case, look for the method asStickyReference. It will lead you straight to the mechanism. Gofer new smalltalkhubUser: 'CAR' project: 'TaskIT'; configuration; load. (#ConfigurationOfTaskIT asClass project version: #stable) load: 'full' 2014-08-05 11:22 GMT+02:00 Udo Schneider <Udo.Schneider@homeaddress.de>:
On 04.08.2014 21:35, stepharo wrote:> We should write a chapter on finalization but since I do not know it
well (and I forget)... igor will answer you.
Stef
I found "the" bug. It seems it's a side effect of finalization, WeakRegistry and cyclic references. I'll write a TestCase for that.
Thanks,
Udo
On 05.08.2014 12:10, Santiago Bragagnolo wrote:> TaskIT has a feature named StickyReference, for that propouse, is not
trivial at all, because when you fork you are using a block that has a reference to a context. In the end even if your variable is nil, your process is being pointed by the context. You're feeding my deepest fears :-)
I also reduced the testcases to even show a (IMHO) faulty behavior w/o any process at all. Simple references are sufficient. Still I'm wondering what's the official way to solve that problem. IMHO objects with forked background processes which want to terminate those processes implicitly using finalization isn't something uncommon ... CU, Udo
On 05.08.2014 14:08, Udo Schneider wrote:
I also reduced the testcases to even show a (IMHO) faulty behavior w/o any process at all. Simple references are sufficient. I just created a small TestCase showing the (IHMO) faulty behavior. I hope the intention is clear from the package/var names.
Gofer it smalltalkhubUser: 'UdoSchneider' project: 'Playground'; package: 'CyclicFinalizationBug'; load. Check out the tests in CyclicFinalizationBugTestCase. Hope this helps. CU, Udo
Udo Schneider wrote:
On 05.08.2014 14:08, Udo Schneider wrote:
I also reduced the testcases to even show a (IMHO) faulty behavior w/o any process at all. Simple references are sufficient. I just created a small TestCase showing the (IHMO) faulty behavior. I hope the intention is clear from the package/var names.
Gofer it smalltalkhubUser: 'UdoSchneider' project: 'Playground'; package: 'CyclicFinalizationBug'; load.
Check out the tests in CyclicFinalizationBugTestCase.
Hope this helps.
CU,
Udo
Is there a Fogbugz case to track it? cheers -ben
On 06.08.2014 02:36, Ben Coman wrote:
Is there a Fogbugz case to track it? cheers -ben
There is now: https://pharo.fogbugz.com/f/cases/13785/Cyclic-Referencing-self-prevents-an-... CU, Udo
participants (5)
-
Ben Coman -
Santiago Bragagnolo -
stepharo -
Udo Schneider -
Udo Schneider