If you do ever write a book get a good proofreader ;-)
Anonymous
February 21, 2005
The comment has been removed
Anonymous
February 21, 2005
regarding the 1st example, in Thing1::SetThing2, don't you need to release whatever was in this->_Thing2 before overwriting it & addref'ing the passed value? (same thing in Thing2::SetThing1). This is so you don't leak refs when these methods are called repeatedly. Also the AddRef could probably be moved before the Lock call in these methods, thereby reducing the time spent with the lock held. But then again, maybe i'm wrong, since ref count is hard ;-)
Anonymous
February 22, 2005
Alexey, I didn't bother to try to ensure that the examples compiled, to be honest :)
jbn, you're right, I should have released the _Thing1 variable (if it was not null). And the addref could be moved before the lock is held (after changing the AddRef target to thing1). If you were addref'ing thing1 (as opposed to _Thing1) you could even move it AFTER releasing the lock (because the caller has a reference to thing1).
On the other hand, the AddRef of _Thing1 has to happen within the lock - otherwise _Thing1 could be set to NULL between the LeaveCriticalSection and the call to Release.
Anonymous
February 22, 2005
Could you explain a little more about solving the circular reference issues? I'm sure many people have run into these sort of problems.
Anonymous
February 22, 2005
I have had to debug many problems of circular references, and to me deadlock problems and circular references are a lot alike. If you look at http://lists.ximian.com/archives/public/mono-patches/2003-August/023295.html, they explain how they model their lock hierarchy to never violate their lock order; now if you graph how your data structures point to each other and which pointers are owning references (i.e. AddRef'ed pointers), then it's pretty natural to think that when two items are in a refcount cycle, they "deadlock" as in "they lock each other in memory". Whether for mutexes or refs, no deadlocks means no cycles in the associated graph.. In any case, it should be possible to demonstrate via formal methods that a given program cannot deadlock: does this make any sense to you or am i off-topic already? ;-)
Anonymous
February 22, 2005
The comment has been removed
Anonymous
February 23, 2005
Alexey, You're right that it's a design problem. But it's indescribably easy for circular references to come into existance. That's one of the reasons that garbage collection is harder than just reference counting objects - you need to actively sweep through all allocated objects looking for cycles.
Having said that, your comments are spot on.
Anonymous
February 24, 2005
The boost shared_ptr / weak_ptr libraries (coming soon to a C++ standard library near you) are a great way to handle this sort of circular dependency. If A has a strong pointer to B but B only has a weak pointer to A, no circularity is introduced (although B has to be aware that when it tries to access the A it might have gone away).
Works really well for callbacks, and is well-enough designed that it's hard to use it wrongly.