http://quantlib.414.s1.nabble.com/Re-QuantLib-SWIG-the-observer-pattern-and-destructor-call-during-update-tp8917p8921.html
Subversion or move to a DVCS).
garbage collector in another thread.
languages for anything else than toy programs.
> We might use 2.x for an overall library re-factoring, with the spotlight on
> 1) thread-safety
> 2) parallelism
> 3) increased boost-ification (math, distributions, date, random
> numbers, optional, etc)
> 4) review of few issues about Instrument/Pricing engines, etc
> 5) interface clean-up removing methods which can be implemented as functions
> 6) review of the worst performance bottlenecks (e.g. virtual
> Event::hasOccurred, etc)
> 7) fix the non invertible relation between dates and times in TermStructure
> 8) etc
>
> ciao -- Nando
>
> On Wed, Feb 29, 2012 at 12:45 PM, Luigi Ballabio
> <
[hidden email]> wrote:
>> Hi all,
>> recently Klaus Spanderen has posted on his blog about the
>> Observer/Observable problems we had when QuantLib is exported through
>> SWIG to a language like Java or C# which run garbage collection in a
>> separate thread (see
>> <
http://old.nabble.com/Issues-with-C--Swig-Bindings,-NUnit-and-Settings.instance%28%29.setEvaluationDate%28%29-td30549787.html>
>> for the original thread and
>> <
http://hpcquantlib.wordpress.com/2012/02/27/quantlib-swig-and-a-thread-safe-observer-pattern-in-c/>
>> for Klaus' post).
>>
>> I've been thinking about it for the last few months, too. I haven't a
>> full solution (I guess the real solution would be to rewrite the whole
>> thing in terms of Boost.Signal2, which is thread-safe) but here's what
>> I got so far.
>>
>> The original problem is that we've gone against one of the basic
>> tenets of C++, namely, that release of resources should go in the
>> inverse order as their acquisition. What happens now is that observers
>> unregister themselves in the destructor they inherit from the base
>> Observer class, which results in the following sequence of actions:
>>
>> On construction:
>> - call the Observer constructor, which builds the base-class part of
>> the instance;
>> - call the derived-class constructor, which builds the derived-class
>> attributes and stuff;
>> - inside the derived-class constructor, register with the observables.
>>
>> On destruction:
>> - call the derived-class destructor, which destroys the derived-class
>> attributes and stuff;
>> - call the Observer destructor, which unregisters with the observables...
>> - ...and then destroys the base-class part of the instance.
>>
>> The problem is that we have a-b-c during construction and b-c-a during
>> destruction (it should be c-b-a). Doing it this way, sometimes it
>> happens that an observable sends a notification between b and c. The
>> observer is not yet unregistered, so it gets the notification; but
>> since it's already been partially destroyed, the resulting call to
>> update() results in a crash.
>>
>> Both Henner and Klaus did their best to fix the Observer class, but I
>> think the solution is to do things in the correct order (c-b-a), that
>> is, unregister in the destructor of the derived class. But how?
>> Forcing one to write the calls to unregisterWith() inside the
>> destructor (and often, to write an explicit destructor just for that)
>> cannot be enforced, and would result in dangling pointers as soon as
>> one forgets to do it.
>>
>> One way might be to use RAII to do this. We might implement a helper
>> class like:
>>
>> template <class T>
>> class Registered {
>> T observable_;
>> Observer* observer_;
>> public:
>> Registered(const T& observable, Observer* observer)
>> : observable_(observable), observer_(observer) {
>> observer_->registerWith(observable_);
>> }
>> ~Registered() {
>> observer_->unregisterWith(observable_);
>> }
>> const T& operator->() const { return observable_; }
>> };
>>
>> that wraps an observable and manages unregistration. This way,
>> instead of writing derived observer classes as:
>>
>> class SomeClass {
>> Handle<YieldTermStructure> ts_;
>> public:
>> SomeClass(const Handle<YieldTermStructure>& ts) : ts_(ts) {
>> registerWith(ts_);
>> }
>> };
>>
>> we would write:
>>
>> class SomeClass {
>> Registered<Handle<YieldTermStructure> > ts_;
>> public:
>> SomeClass(const Handle<YieldTermStructure>& ts) : ts_(ts, this) {}
>> };
>>
>> This way, ts_ is a Registered instance (which provides an
>> operator->(), so it can be used as before; for instance,
>> ts_->discount(t) still works) and when SomeClass is destroyed, the
>> unregisterWith call in the Registered destructor will fire during the
>> destruction of SomeClass, doing things in the correct order.
>>
>> (Note: it would also be possible to work out things so that we can
>> leave the registerWith() call in the constructor, if we want to modify
>> the least possible amount of code. When called with a Registered as an
>> argument, it would register the observer with the wrapped observable
>> and store the observer's "this" pointer into the Registered instance.)
>> (Note 2: "Registered" might not be the best name. "Observed", maybe?)
>>
>>
>> Unfortunately, it's not foolproof. For instance, the Registered
>> instances are better declared last in the class; and even in that
>> case, if we have two Registered (A and B) there might be freak
>> scenarios in which A is unregistered and destroyed, and before B can
>> be unregistered it fires a notification. If the observer's update()
>> method just flips a bool, it will work fine; but if update() tries to
>> access A instead, it will find it destroyed and hilarity will ensue.
>>
>> Also, we would still have the problem that an observer might be
>> removed from an observable's registered list while the observable is
>> iterating over it in notifyObservers(). We'll need a lock to prevent
>> that.
>>
>> I guess this about wraps it up. Thoughts?
>>
>> Later,
>> Luigi
>>
>> ------------------------------------------------------------------------------
>> Virtualization & Cloud Management Using Capacity Planning
>> Cloud computing makes use of virtualization - but cloud computing
>> also focuses on allowing computing to be delivered as a service.
>>
http://www.accelacomm.com/jaw/sfnl/114/51521223/>> _______________________________________________
>> QuantLib-dev mailing list
>>
[hidden email]
>>
https://lists.sourceforge.net/lists/listinfo/quantlib-devalso focuses on allowing computing to be delivered as a service.