Provide a thread safe SGWeakPtr implementation.

Extend SGAtomic with atomic exchange and add.
Import updates from the original implementation of that in OpenFDM.

Modified Files:
 	Makefile.am SGAtomic.cxx SGAtomic.hxx SGReferenced.hxx
 	SGSharedPtr.hxx
Added Files:
 	SGWeakPtr.hxx SGWeakReferenced.hxx
This commit is contained in:
frohlich
2009-06-24 05:19:52 +00:00
committed by Tim Moore
parent 33f7903aeb
commit 0f7b65a921
7 changed files with 238 additions and 25 deletions

View File

@@ -17,6 +17,8 @@ include_HEADERS = \
SGSharedPtr.hxx \
SGSmplhist.hxx \
SGSmplstat.hxx \
SGWeakPtr.hxx \
SGWeakReferenced.hxx \
Singleton.hxx
libsgstructure_a_SOURCES = \

View File

@@ -1,6 +1,6 @@
/* -*-c++-*-
*
* Copyright (C) 2005-2006 Mathias Froehlich
* Copyright (C) 2005-2009 Mathias Froehlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -53,6 +53,18 @@ unsigned __sync_add_and_fetch_4(volatile void *ptr, unsigned value)
return result + value;
}
unsigned __sync_bool_compare_and_swap_4(volatile void *ptr,
unsigned oldValue, unsigned newValue)
{
register volatile unsigned* mem = reinterpret_cast<volatile unsigned*>(ptr);
unsigned before;
__asm__ __volatile__("lock; cmpxchg{l} {%1,%2|%1,%2}"
: "=a"(before)
: "q"(newValue), "m"(*mem), "0"(oldValue)
: "memory");
return before == oldValue;
}
void __sync_synchronize()
{
__asm__ __volatile__("": : : "memory");

View File

@@ -1,6 +1,6 @@
/* -*-c++-*-
*
* Copyright (C) 2005-2006 Mathias Froehlich
* Copyright (C) 2005-2009 Mathias Froehlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -81,7 +81,25 @@ public:
SGGuard<SGMutex> lock(mMutex);
return mValue;
#endif
}
}
bool compareAndExchange(unsigned oldValue, unsigned newValue)
{
#if defined(SGATOMIC_USE_GCC4_BUILTINS)
return __sync_bool_compare_and_swap(&mValue, oldValue, newValue);
#elif defined(SGATOMIC_USE_MIPOSPRO_BUILTINS)
return __compare_and_swap(&mValue, oldValue, newValue);
#elif defined(SGATOMIC_USE_WIN32_INTERLOCKED)
long volatile* lvPtr = reinterpret_cast<long volatile*>(&mValue);
return oldValue == InterlockedCompareExchange(lvPtr, newValue, oldValue);
#else
SGGuard<SGMutex> lock(mMutex);
if (mValue != oldValue)
return false;
mValue = newValue;
return true;
#endif
}
private:
SGAtomic(const SGAtomic&);
@@ -91,9 +109,6 @@ private:
&& !defined(SGATOMIC_USE_MIPOSPRO_BUILTINS) \
&& !defined(SGATOMIC_USE_WIN32_INTERLOCKED)
mutable SGMutex mMutex;
#endif
#ifdef SGATOMIC_USE_WIN32_INTERLOCKED
__declspec(align(32))
#endif
unsigned mValue;
};

View File

@@ -20,13 +20,8 @@
#ifndef SGReferenced_HXX
#define SGReferenced_HXX
#define USE_OPENTHREADS_ATOMIC
#ifndef USE_OPENTHREADS_ATOMIC
#include "SGAtomic.hxx"
#else
#include <OpenThreads/Atomic>
#endif
/// Base class for all reference counted SimGear objects
/// Classes derived from this one are meant to be managed with
@@ -54,11 +49,7 @@ public:
{ if (ref) return 1u < ref->_refcount; else return false; }
private:
#ifndef USE_OPENTHREADS_ATOMIC
mutable SGAtomic _refcount;
#else
mutable OpenThreads::Atomic _refcount;
#endif
};
#endif

View File

@@ -1,6 +1,6 @@
/* -*-c++-*-
*
* Copyright (C) 2005-2006 Mathias Froehlich
* Copyright (C) 2005-2009 Mathias Froehlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -37,11 +37,14 @@
/// to zero and consequently the objects will never be destroyed.
/// Always try to use directed graphs where the references away from the
/// top node are made with SGSharedPtr's and the back references are done with
/// ordinary pointers.
/// ordinary pointers or SGWeakPtr's.
/// There is a very good description of OpenSceneGraphs ref_ptr which is
/// pretty much the same than this one at
/// http://dburns.dhs.org/OSG/Articles/RefPointers/RefPointers.html
template<typename T>
class SGWeakPtr;
template<typename T>
class SGSharedPtr {
public:
@@ -49,19 +52,19 @@ public:
{}
SGSharedPtr(T* ptr) : _ptr(ptr)
{ get(_ptr); }
SGSharedPtr(const SGSharedPtr& p) : _ptr(p.ptr())
SGSharedPtr(const SGSharedPtr& p) : _ptr(p.get())
{ get(_ptr); }
template<typename U>
SGSharedPtr(const SGSharedPtr<U>& p) : _ptr(p.ptr())
SGSharedPtr(const SGSharedPtr<U>& p) : _ptr(p.get())
{ get(_ptr); }
~SGSharedPtr(void)
{ put(); }
SGSharedPtr& operator=(const SGSharedPtr& p)
{ assign(p.ptr()); return *this; }
{ assign(p.get()); return *this; }
template<typename U>
SGSharedPtr& operator=(const SGSharedPtr<U>& p)
{ assign(p.ptr()); return *this; }
{ assign(p.get()); return *this; }
template<typename U>
SGSharedPtr& operator=(U* p)
{ assign(p); return *this; }
@@ -74,26 +77,38 @@ public:
{ return _ptr; }
T* ptr(void) const
{ return _ptr; }
T* get(void) const
{ return _ptr; }
T* release()
{ T* tmp = _ptr; _ptr = 0; T::put(tmp); return tmp; }
bool isShared(void) const
{ return SGReferenced::shared(_ptr); }
{ return T::shared(_ptr); }
unsigned getNumRefs(void) const
{ return SGReferenced::count(_ptr); }
{ return T::count(_ptr); }
bool valid(void) const
{ return _ptr; }
void clear()
{ put(); }
void swap(SGSharedPtr& sharedPtr)
{ T* tmp = _ptr; _ptr = sharedPtr._ptr; sharedPtr._ptr = tmp; }
private:
void assign(T* p)
{ get(p); put(); _ptr = p; }
void get(const T* p) const
{ SGReferenced::get(p); }
{ T::get(p); }
void put(void)
{ if (!SGReferenced::put(_ptr)) { delete _ptr; _ptr = 0; } }
{ if (!T::put(_ptr)) { delete _ptr; _ptr = 0; } }
// The reference itself.
T* _ptr;
template<typename U>
friend class SGWeakPtr;
};
#endif

View File

@@ -0,0 +1,75 @@
// Copyright (C) 2004-2009 Mathias Froehlich - Mathias.Froehlich@web.de
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#ifndef SGWeakPtr_HXX
#define SGWeakPtr_HXX
#include "SGWeakReferenced.hxx"
template<typename T>
class SGWeakPtr {
public:
SGWeakPtr(void)
{ }
SGWeakPtr(const SGWeakPtr& p) : mWeakData(p.mWeakData)
{ }
template<typename U>
SGWeakPtr(const SGSharedPtr<U>& p)
{ SGSharedPtr<T> sharedPtr = p; assign(sharedPtr.get()); }
template<typename U>
SGWeakPtr(const SGWeakPtr<U>& p)
{ SGSharedPtr<T> sharedPtr = p.lock(); assign(sharedPtr.get()); }
~SGWeakPtr(void)
{ }
template<typename U>
SGWeakPtr& operator=(const SGSharedPtr<U>& p)
{ SGSharedPtr<T> sharedPtr = p; assign(sharedPtr.get()); return *this; }
template<typename U>
SGWeakPtr& operator=(const SGWeakPtr<U>& p)
{ SGSharedPtr<T> sharedPtr = p.lock(); assign(sharedPtr.get()); return *this; }
SGWeakPtr& operator=(const SGWeakPtr& p)
{ mWeakData = p.mWeakData; return *this; }
SGSharedPtr<T> lock(void) const
{
if (!mWeakData)
return SGSharedPtr<T>();
SGSharedPtr<T> sharedPtr;
sharedPtr.assignNonRef(mWeakData->getPointer<T>());
return sharedPtr;
}
void clear()
{ mWeakData = 0; }
void swap(SGWeakPtr& weakPtr)
{ mWeakData.swap(weakPtr.mWeakData); }
private:
void assign(T* p)
{
if (p)
mWeakData = p->mWeakData;
else
mWeakData = 0;
}
// The indirect reference itself.
SGSharedPtr<SGWeakReferenced::WeakData> mWeakData;
};
#endif

View File

@@ -0,0 +1,103 @@
// Copyright (C) 2004-2009 Mathias Froehlich - Mathias.Froehlich@web.de
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#ifndef SGWeakReferenced_HXX
#define SGWeakReferenced_HXX
#include "SGReferenced.hxx"
#include "SGSharedPtr.hxx"
template<typename T>
class SGWeakPtr;
class SGWeakReferenced {
public:
/// The object backref and the reference count for this object need to be
/// there in any case. Also these are per object and shall not be copied nor
/// assigned.
/// The reference count for this object is stored in a secondary object that
/// is shared with all weak pointers to this current object. This way we
/// have an atomic decision using the reference count of this current object
/// if the backref is still valid. At the time where the atomic count is
/// equal to zero the object is considered dead.
SGWeakReferenced(void) :
mWeakData(new WeakData(this))
{}
SGWeakReferenced(const SGWeakReferenced& weakReferenced) :
mWeakData(new WeakData(this))
{}
~SGWeakReferenced(void)
{ mWeakData->mWeakReferenced = 0; }
/// Do not copy the weak backward references ...
SGWeakReferenced& operator=(const SGWeakReferenced&)
{ return *this; }
/// The usual operations on weak pointers.
/// The interface should stay the same then what we have in Referenced.
static unsigned get(const SGWeakReferenced* ref)
{ if (ref) return ++(ref->mWeakData->mRefcount); else return 0u; }
static unsigned put(const SGWeakReferenced* ref)
{ if (ref) return --(ref->mWeakData->mRefcount); else return ~0u; }
static unsigned count(const SGWeakReferenced* ref)
{ if (ref) return ref->mWeakData->mRefcount; else return 0u; }
private:
/// Support for weak references, not increasing the reference count
/// that is done through that small helper class which holds an uncounted
/// reference which is zeroed out on destruction of the current object
class WeakData : public SGReferenced {
public:
WeakData(SGWeakReferenced* weakReferenced) :
mRefcount(0u),
mWeakReferenced(weakReferenced)
{ }
template<typename T>
T* getPointer()
{
// Try to increment the reference count if the count is greater
// then zero. Since it should only be incremented iff it is nonzero, we
// need to check that value and try to do an atomic test and set. If this
// fails, try again. The usual lockless algorithm ...
unsigned count;
do {
count = mRefcount;
if (count == 0)
return 0;
} while (!mRefcount.compareAndExchange(count, count + 1));
// We know that as long as the refcount is not zero, the pointer still
// points to valid data. So it is safe to work on it.
return static_cast<T*>(mWeakReferenced);
}
SGAtomic mRefcount;
SGWeakReferenced* mWeakReferenced;
private:
WeakData(void);
WeakData(const WeakData&);
WeakData& operator=(const WeakData&);
};
SGSharedPtr<WeakData> mWeakData;
template<typename T>
friend class SGWeakPtr;
};
#endif