2010/10/11 Levente Uzonyi <[email protected]>: > On Mon, 11 Oct 2010, Igor Stasenko wrote: > >> 2010/10/11 Levente Uzonyi <[email protected]>: >> On Mon, 11 Oct 2010, Igor Stasenko wrote: >> >>> On 10 October 2010 23:43, Levente Uzonyi <[email protected]> wrote: >>> On Sun, 10 Oct 2010, Igor Stasenko wrote: >>> >>>> A current implementation of this method >>>> >>>> remove: oldObject ifAbsent: exceptionBlock >>>> "Remove oldObject as one of the receiver's elements." >>>> >>>> oldObject ifNil: [ ^nil ]. >>>> ^(self protected: [ valueDictionary removeKey: oldObject >>>> ifAbsent: >>>> nil ]) >>>> ifNil: [ exceptionBlock value ] >>>> >>>> simply removes a previously registered object from registry and voila. >>>> >>>> Now lets get back to our discussion about multiple finalizers per >>>> object and using them in weak subscriptions etc. >>>> >>>> Suppose i am added a socket to weak registry, >>>> and suppose i am added a weak subscription to it. >>>> >>>> Now, if i do 'socket close' , it tells weak registry to remove it from >>>> list. >>>> And what we'll have: >>>> - socket handle is closed >>>> - socket is wiped from weak registry >>>> - but weak subscription still listed somewhere in a list of >>>> subscriptions >>>> >>>> >>>> My suggestion is, that upon #remove:, >>>> a weak registry should notify all executors that object of interest >>>> are no longer takes part in finalization scheme, >>>> so they should not count on receiving #finalize eventually. >>>> >>>> In other words: >>>> >>>> remove: oldObject ifAbsent: exceptionBlock >>>> "Remove oldObject as one of the receiver's elements." >>>> >>>> oldObject ifNil: [ ^nil ]. >>>> ^(self protected: [ | executor | >>>> executor := valueDictionary removeKey: oldObject ifAbsent: >>>> nil. >>>> executor discardFinalization. >>>> ]) >>>> ifNil: [ exceptionBlock value ] >>> >>> It's only an issue with the new WeakRegistry implementation, previous >>> implementations don't have such problem. I think changing the method as >>> you >>> suggested, implementing WeakFinalizerItem >> #discardFinalization as >>> "executor := nil" and changing WeakFinalizerItem >> #finalizaValues to >>> ignore the executor if it's nil will fix the problem. Am I right? >>> >>> I don't get how "multiple finalizers per object" is related to this >>> problem >>> at all. >>> >> >> No, you miss the point. >> When you removing object from weak registry, it is important , time to >> time to tell all of its executors, >> that they will no longer receive #finalize, because object is no >> longer a member of weak registry. >> >> If you simply set executor := nil, it does nothing, an executor itself >> did not notified that he won't be needed >> in any possible future. >> So, if your finalization action is to remove some object(s) from the >> list , you'll get your list dirty after object will die, >> because #finalize will be never sent to your executor. >> >> Here the simple test case: >> >> | coll obj someWrapper | >> coll := OrderedCollection new. >> obj := Object new. >> someWrapper := WeakArray with: obj. >> coll add: someWrapper. >> >> obj toFinalizeSend: #remove: to: coll with: someWrapper. >> obj finalizationRegistry remove: obj. >> obj := nil. >> Smalltalk garbageCollect. >> self assert: coll isEmpty >> >> >> the point is, that once you doing a #remove: , >> your finalization scheme is broken. >> >> >> I don't get you. When you remove an object from a WeakRegistry, you tell >> the >> system that you want the object removed and all related executors deleted. >> So the executors should never receive #finalize, they should be thrown >> away. >> Even if there's action to be done with the executors (which is pointless >> IMHO since those will be thrown away, but who knows), doing them is the >> responsibility of the sender of #remove:. >> > > Let us get back to multiple finalizers per object, > when you have two separate places, which adding possibly different > executors for a single object > without knowing about each other (otherwise why would you want to add > two finalizers instead of one). > Now if one decides to do #remove: , > how to ensure that second one won't be left with dirty/invalid state? > > > It's not ensured, and it doesn't have to be. The sender of #remove: takes > all responsibility. It can decide to add some executors back to the registry > if that's necessary. > If you want to keep your executors safe from some other code, which may > #remove: your objects from a WeakRegistry, then you can create a private > WeakRegistry and store your executors there, just like Sockets and > FileStreams do. >
Conclusion: weak registry don't have to support multiple finalizers per single object. Instead, if one sees the need to control a finalization of certain object(s) in own way, indepentently fron any other, then he should use a private weak registry (like Sockets and FileStreams do), and register object and its executor there. -- Best regards, Igor Stasenko AKA sig. _______________________________________________ Pharo-project mailing list [email protected] http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
