notifiable.hpp
来自「The library provides supports for run-ti」· HPP 代码 · 共 271 行
HPP
271 行
#ifndef NOTIFIABLE_HPP#define NOTIFIABLE_HPP// define NOTIF_SILENT to suppress warnings below#include "NotifiableI.hpp"#include "TemplUtils.hpp"// For compatibility with DynObj.h#ifndef docall #ifndef NOTIF_SILENT #warning docall not defined, defining to nothing #endif #define docall#endif// If threaded implementation, NOTIF_LOCK locks a global recursive mutex// so that NotifierI and Notifiable can decouple in an ordered way.#ifndef NOTIF_LOCK #include "pi/CritSect.h" // Use a shared global in Notifiable.cpp extern CritSect g_not_cs; #define NOTIF_LOCK g_not_cs.Enter() #define NOTIF_UNLOCK g_not_cs.Leave()#endif #ifndef NOTIF_TRACE #ifndef NOTIF_SILENT #warning NOTIF_TRACE not defined, defining to nothing #endif #define NOTIF_TRACE(str)#endif // Reader-write lock for WeakRef#include "pi/RWLock.h"class NotifLocker {public: NotifLocker(){ NOTIF_LOCK; } ~NotifLocker(){ NOTIF_UNLOCK; }};// Helper struct, represents one subscriber to a specific notification.struct NotTarget { NotTarget(NotifiableI* pni, int evt) : m_pni(pni), m_evt(evt) { } NotTarget(const NotTarget& nt) : m_pni(nt.m_pni), m_evt(nt.m_evt) { } NotifiableI *m_pni; int m_evt; bool operator == (const NotTarget& nt) { return nt.m_pni==m_pni && nt.m_evt==m_evt; }};/** @ingroup VObj * Base class to include support for notfications. * A class that derives from Notifier send off destructor notifications * so we can have weak references to them. For thread safety, it uses a lock * that is shared between all instances of Notifier. */class Notifier : public NotifierI {public: Notifier() : m_fst(NULL) { } ~Notifier() { Notify(NOT_EVT_DESTRUCTOR,NULL); NotifLocker lock; delete m_fst; m_fst=NULL; } /** Adds a notifcation target to this object */ virtual bool docall AddNotifiable(NotifiableI* pnot, int evt){ if( !pnot ) return false; NOTIF_TRACE("Adding notifiable"); NotifLocker lock; // Only add once if( TLLFind(NotTarget(pnot,evt),m_fst) ) return false; m_fst=new TLLNode<NotTarget>(NotTarget(pnot,evt),m_fst); return true; } /** Remove a notifcation target to this object */ virtual bool docall RemoveNotifiable(NotifiableI* pnot, int evt){ NOTIF_TRACE("Removing notifiable"); NotifLocker lock; return TLLErase<NotTarget>(NotTarget(pnot,evt),&m_fst); } /** Notifies all notifcation targets registered with this object */ virtual int docall Notify( int evt, NotDataI *pnd ){ NotifLocker lock; // We send pointer to ourseleves as first arg int cnt=0; for( TLLNode<NotTarget> *pnode=m_fst; pnode; pnode=pnode->m_nxt ) if( pnode->m_t.m_evt==evt || pnode->m_t.m_evt==NOT_EVT_ALL ) cnt++, pnode->m_t.m_pni->OnNotify( this, evt, pnd ); return cnt; } protected: TLLNode<NotTarget> *m_fst;};// The point with the below class is that it can convert back to the main class pointer// However, then we loose the type (NotifierI). The receiver can resolve type/*template<class T>class Notifier : public NotifierBaseImpl {public: ~Notifier(){ Notify(NOT_DESTRUCTOR,NULL); } virtual void docall Notify( int msg, NotDataI *pnd ){ NotifLocker lock; // NOTE: Conversion to T* will cast back to whole object (if multiple bases) // T and Notifier will be in the same object and on the same SDO side T* pt = static_cast<T*>(this); for( TLLNode<NotifiableI*> *pnode=m_fst; pnode; pnode=pnode->m_nxt ) pnode->m_t->OnNotify( pt, msg, pnd ); }};*//** @ingroup VObj * Weak reference to another object of type T. * The other object must support NotifierI, otherwise we cannot * make a reference. To generate a NotifierI from T, there is * GenericCaster which by default uses static_cast<NotfierI*>(T*). * DynObj will specialize this to provide the interface in a * different way (using do_cast). * A WeakRef can be used in a thread safe way, using HoldGet() and * HoldPut(). It has a reader-writer lock object per instance, so * the reference cannot be overwritten nor destroyed while we do * HoldGet(). */template<class T> class WeakRef : public NotifiableI {public: WeakRef(T* pobj=NULL) : m_pobj(NULL), m_pni(NULL) { Reset(pobj); } ~WeakRef(){ Reset(NULL); NOTIF_TRACE("WeakRef Dtor"); } /** Set the reference to another object */ WeakRef& Reset( T* pobj ){ piWriteLocker<RWLock> locker( m_lock ); if( m_pobj==pobj ) return *this; assert( locker.Locked() ); if( m_pni || m_pobj ){ assert( m_pni && m_pobj ); m_pni->RemoveNotifiable(this,NOT_EVT_DESTRUCTOR); m_pni = NULL; m_pobj = NULL; } if( !pobj ) return *this; // This will use a static_cast if available and if not, it can be // specialized (with value 1) m_pni = GenericCaster<NotifierI*,T*, 1-IsConvertible<NotifierI*,T*>::v>::Cast(pobj); if( !m_pni ){ NOTIF_TRACE("WeakRef::Reset - Could not cast to object to NotifierI. Resetting object."); m_pobj = NULL; return *this; } m_pobj = pobj; m_pni->AddNotifiable(this,NOT_EVT_DESTRUCTOR); return *this; } /** Operator support */ WeakRef& operator = (T *pobj){ return Reset(pobj); } bool operator ==(T *pobj){ return m_pobj==pobj; } /** These are non-synced methods. Only use from the same thread as where * the reference owner. */ operator T*(){ return m_pobj; } /** Non-synced */ T* operator ->(){ return m_pobj; } /** Non-synced */ T* Get(){ return m_pobj; } /** Return true if the reference is empty (we have NULL pointer) */ bool operator!(){ return !m_pobj; } /** Synchronized access. * This increases read counter (and must be compensated with HoldPut) */ T* HoldGet(){ if( !m_pobj ) return NULL; if( !m_lock.Lock() ) return NULL; return m_pobj; } /** Synchronized end-of-access. * This decreases read counter. On zero, the reference can be modified. */ void HoldPut( T *pt ){ if( !pt ) return; assert( pt==m_pobj ); bool b = m_lock.Unlock(); assert( b ); } protected: virtual bool docall OnNotify( NotifierI *psrc, int evt, NotDataI *pnd ){ if( evt==NOT_EVT_DESTRUCTOR ){ piWriteLocker<RWLock> locker(m_lock); if( psrc!=m_pni ){ NOTIF_TRACE("WeakRef::OnNotify: Unknown source, keeping object"); return false; } m_pobj = NULL; m_pni = NULL; return true; } else{ NOTIF_TRACE("WeakRef::OnNotify: Unknown event, doing nothing"); return false; } } T* m_pobj; // 16 bytes all in all NotifierI *m_pni; RWLock m_lock;};/*// The difference compared to WeakRef is that here we don't keep a// pointer to the compound object, instead we have a pointer to // a sub object. We cannot do the 'inside' test, but have to // explicitely store a pointer to the NotifierI. template<class T> class WeakRefSubObject : public WeakRef<T> {public: WeakRefSubObject(T* pobj=NULL) : WeakRef<T>(pobj), m_pni(NULL) { } ~WeakRefSubObject(){ } void Reset(T* pobj ){ NotifLocker lock; // # Recursive lock! WeakRef<T>::Reset( pobj ); if( this->m_pobj ) m_pni = Cast<NotifierI*>(this->m_pobj,NULL); } void operator = (T *pobj){ Reset(pobj); } virtual bool docall OnNotify( NotifierI *psrc, int evt, NotDataI *pnd ){ NotifLocker lock; if( evt==NOT_DESTRUCTOR ){ if( psrc==m_pni ){ this->m_pobj = NULL; m_pni=NULL; NOTIF_TRACE("WeakRefSubObject::OnNotify: Releasing"); return true; } else{ NOTIF_TRACE("WeakRefSubObject::OnNotify: Unknown source, releasing reference anyway"); this->m_pobj = NULL; m_pni=NULL; return false; } } else{ NOTIF_TRACE("WeakRefSubObject::OnNotify: Unknown event, doing nothing"); return false; } } protected: NotifierI *m_pni;};*/#endif // NOTIFIABLE_HPP
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?