Observer pattern and destruction during update

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

Observer pattern and destruction during update

Bojan Nikolic

Dear All,

I've been doing some experiments with cleaner destruction of objects in
SWIG target languages with out-of-thread garbage
collection. Unfortunately, I've not been able to come up with an
automatic solution for the problem since encapsulated
Observer/Observables relationships can cause problems just as well as
top level Observers created in the target language. Therefore, one still
has somehow go through the classes by hand identifying ones which cause
problems and writing special destructors for them.

Still, for completeness here are the patches describing what I've
done. With these patches QuoteHandle destruction is I believe fully
reliable.


* Add an unregister function to the Handle class -- this is necessary so
  that the Observer relationship in the link can be removed before the
  destruction of the class begins:

--- a/QuantLib/ql/handle.hpp
+++ b/QuantLib/ql/handle.hpp
@@ -49,6 +49,7 @@
             bool empty() const { return !h_; }
             const boost::shared_ptr<T>& currentLink() const { return h_; }
             void update() { notifyObservers(); }
+            void unregister(void);
           private:
             boost::shared_ptr<T> h_;
             bool isObserver_;
@@ -89,6 +90,8 @@
         bool empty() const;
         //! allows registration as observable
         operator boost::shared_ptr<Observable>() const;
+        //! Unregister as observer
+        void unregister(void) {link_->unregister();}
         //! equality test
         template <class U>
         bool operator==(const Handle<U>& other) { return link_==other.link_; }
@@ -134,6 +137,13 @@
     }

     template <class T>
+    inline void Handle<T>::Link::unregister(void) {
+        if (h_ && isObserver_)
+            unregisterWith(h_);
+        isObserver_=false;
+    }
+
+    template <class T>
     inline void Handle<T>::Link::linkTo(const boost::shared_ptr<T>& h,
                                         bool registerAsObserver) {
         if ((h != h_) || (isObserver_ != registerAsObserver)) {



* Add a mutex on the observers_ data structure in the Observable class
  so that the integrity of this structure is maintained when one thread
  is modifying the structure while others are reading it (Thanks to
  Klaus Spanderen for pointing out this will be necessary) . Note that
  this will require QuantLib to be linked with boost threads library.

--- a/QuantLib/ql/patterns/observable.hpp
+++ b/QuantLib/ql/patterns/observable.hpp
@@ -30,6 +30,7 @@
 #include <ql/types.hpp>

 #include <boost/shared_ptr.hpp>
+#include <boost/thread.hpp>

 #include <set>

@@ -56,6 +57,7 @@
         std::pair<iterator, bool> registerObserver(Observer*);
         Size unregisterObserver(Observer*);
         std::set<Observer*> observers_;
+        boost::mutex  mx_observers_;
     };

     //! Object that gets notified when a given observable changes
@@ -108,14 +110,17 @@

     inline std::pair<std::set<Observer*>::iterator, bool>
     Observable::registerObserver(Observer* o) {
+        boost::mutex::scoped_lock lock(mx_observers_);
         return observers_.insert(o);
     }

     inline Size Observable::unregisterObserver(Observer* o) {
+        boost::mutex::scoped_lock lock(mx_observers_);
         return observers_.erase(o);
     }

     inline void Observable::notifyObservers() {
+        boost::mutex::scoped_lock lock(mx_observers_);
         bool successful = true;
         std::string errMsg;
         for (iterator i=observers_.begin(); i!=observers_.end(); ++i) {


* Illustration of how to add a specialised destructor (for Java in this
  case) which calls the unregister function to break Observer
  relationship before beginning the destruction of the class:

--- a/QuantLib-SWIG/SWIG/marketelements.i
+++ b/QuantLib-SWIG/SWIG/marketelements.i
@@ -38,6 +38,22 @@
 %template(Quote) boost::shared_ptr<Quote>;
 IsObservable(boost::shared_ptr<Quote>);

+%typemap(javadestruct,
+         methodname="delete",
+         methodmodifiers="public synchronized")  Handle<Quote>
+{
+  if (swigCPtr != 0) {
+    if (swigCMemOwn) {
+      unregister();
+      swigCMemOwn = false;
+      $jnicall;
+    }
+    swigCPtr = 0;
+  }
+}
+
+
+
 %template(QuoteHandle) Handle<Quote>;
 IsObservable(Handle<Quote>);
 %template(RelinkableQuoteHandle) RelinkableHandle<Quote>;


* Extend the SWIG interface to include the new unregister function:

--- a/QuantLib-SWIG/SWIG/common.i
+++ b/QuantLib-SWIG/SWIG/common.i
@@ -99,6 +99,7 @@
     #else
     bool empty();
     #endif
+    void unregister();
 };

 template <class T>

--
Bojan Nikolic          ||          http://www.bnikolic.co.uk

------------------------------------------------------------------------------
This SF email is sponsosred by:
Try Windows Azure free for 90 days Click Here
http://p.sf.net/sfu/sfd2d-msazure
_______________________________________________
QuantLib-dev mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/quantlib-dev