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-25 10:13:03 +02:00
committed by Tim Moore
parent 33f7903aeb
commit 0f7b65a921
7 changed files with 238 additions and 25 deletions
+2
View File
@@ -17,6 +17,8 @@ include_HEADERS = \
SGSharedPtr.hxx \ SGSharedPtr.hxx \
SGSmplhist.hxx \ SGSmplhist.hxx \
SGSmplstat.hxx \ SGSmplstat.hxx \
SGWeakPtr.hxx \
SGWeakReferenced.hxx \
Singleton.hxx Singleton.hxx
libsgstructure_a_SOURCES = \ libsgstructure_a_SOURCES = \
+13 -1
View File
@@ -1,6 +1,6 @@
/* -*-c++-*- /* -*-c++-*-
* *
* Copyright (C) 2005-2006 Mathias Froehlich * Copyright (C) 2005-2009 Mathias Froehlich
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * 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; 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() void __sync_synchronize()
{ {
__asm__ __volatile__("": : : "memory"); __asm__ __volatile__("": : : "memory");
+20 -5
View File
@@ -1,6 +1,6 @@
/* -*-c++-*- /* -*-c++-*-
* *
* Copyright (C) 2005-2006 Mathias Froehlich * Copyright (C) 2005-2009 Mathias Froehlich
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
@@ -81,7 +81,25 @@ public:
SGGuard<SGMutex> lock(mMutex); SGGuard<SGMutex> lock(mMutex);
return mValue; return mValue;
#endif #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: private:
SGAtomic(const SGAtomic&); SGAtomic(const SGAtomic&);
@@ -91,9 +109,6 @@ private:
&& !defined(SGATOMIC_USE_MIPOSPRO_BUILTINS) \ && !defined(SGATOMIC_USE_MIPOSPRO_BUILTINS) \
&& !defined(SGATOMIC_USE_WIN32_INTERLOCKED) && !defined(SGATOMIC_USE_WIN32_INTERLOCKED)
mutable SGMutex mMutex; mutable SGMutex mMutex;
#endif
#ifdef SGATOMIC_USE_WIN32_INTERLOCKED
__declspec(align(32))
#endif #endif
unsigned mValue; unsigned mValue;
}; };
-9
View File
@@ -20,13 +20,8 @@
#ifndef SGReferenced_HXX #ifndef SGReferenced_HXX
#define SGReferenced_HXX #define SGReferenced_HXX
#define USE_OPENTHREADS_ATOMIC
#ifndef USE_OPENTHREADS_ATOMIC
#include "SGAtomic.hxx" #include "SGAtomic.hxx"
#else
#include <OpenThreads/Atomic>
#endif
/// Base class for all reference counted SimGear objects /// Base class for all reference counted SimGear objects
/// Classes derived from this one are meant to be managed with /// 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; } { if (ref) return 1u < ref->_refcount; else return false; }
private: private:
#ifndef USE_OPENTHREADS_ATOMIC
mutable SGAtomic _refcount; mutable SGAtomic _refcount;
#else
mutable OpenThreads::Atomic _refcount;
#endif
}; };
#endif #endif
+25 -10
View File
@@ -1,6 +1,6 @@
/* -*-c++-*- /* -*-c++-*-
* *
* Copyright (C) 2005-2006 Mathias Froehlich * Copyright (C) 2005-2009 Mathias Froehlich
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * 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. /// to zero and consequently the objects will never be destroyed.
/// Always try to use directed graphs where the references away from the /// 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 /// 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 /// There is a very good description of OpenSceneGraphs ref_ptr which is
/// pretty much the same than this one at /// pretty much the same than this one at
/// http://dburns.dhs.org/OSG/Articles/RefPointers/RefPointers.html /// http://dburns.dhs.org/OSG/Articles/RefPointers/RefPointers.html
template<typename T>
class SGWeakPtr;
template<typename T> template<typename T>
class SGSharedPtr { class SGSharedPtr {
public: public:
@@ -49,19 +52,19 @@ public:
{} {}
SGSharedPtr(T* ptr) : _ptr(ptr) SGSharedPtr(T* ptr) : _ptr(ptr)
{ get(_ptr); } { get(_ptr); }
SGSharedPtr(const SGSharedPtr& p) : _ptr(p.ptr()) SGSharedPtr(const SGSharedPtr& p) : _ptr(p.get())
{ get(_ptr); } { get(_ptr); }
template<typename U> template<typename U>
SGSharedPtr(const SGSharedPtr<U>& p) : _ptr(p.ptr()) SGSharedPtr(const SGSharedPtr<U>& p) : _ptr(p.get())
{ get(_ptr); } { get(_ptr); }
~SGSharedPtr(void) ~SGSharedPtr(void)
{ put(); } { put(); }
SGSharedPtr& operator=(const SGSharedPtr& p) SGSharedPtr& operator=(const SGSharedPtr& p)
{ assign(p.ptr()); return *this; } { assign(p.get()); return *this; }
template<typename U> template<typename U>
SGSharedPtr& operator=(const SGSharedPtr<U>& p) SGSharedPtr& operator=(const SGSharedPtr<U>& p)
{ assign(p.ptr()); return *this; } { assign(p.get()); return *this; }
template<typename U> template<typename U>
SGSharedPtr& operator=(U* p) SGSharedPtr& operator=(U* p)
{ assign(p); return *this; } { assign(p); return *this; }
@@ -74,26 +77,38 @@ public:
{ return _ptr; } { return _ptr; }
T* ptr(void) const T* ptr(void) const
{ return _ptr; } { return _ptr; }
T* get(void) const
{ return _ptr; }
T* release()
{ T* tmp = _ptr; _ptr = 0; T::put(tmp); return tmp; }
bool isShared(void) const bool isShared(void) const
{ return SGReferenced::shared(_ptr); } { return T::shared(_ptr); }
unsigned getNumRefs(void) const unsigned getNumRefs(void) const
{ return SGReferenced::count(_ptr); } { return T::count(_ptr); }
bool valid(void) const bool valid(void) const
{ return _ptr; } { return _ptr; }
void clear()
{ put(); }
void swap(SGSharedPtr& sharedPtr)
{ T* tmp = _ptr; _ptr = sharedPtr._ptr; sharedPtr._ptr = tmp; }
private: private:
void assign(T* p) void assign(T* p)
{ get(p); put(); _ptr = p; } { get(p); put(); _ptr = p; }
void get(const T* p) const void get(const T* p) const
{ SGReferenced::get(p); } { T::get(p); }
void put(void) void put(void)
{ if (!SGReferenced::put(_ptr)) { delete _ptr; _ptr = 0; } } { if (!T::put(_ptr)) { delete _ptr; _ptr = 0; } }
// The reference itself. // The reference itself.
T* _ptr; T* _ptr;
template<typename U>
friend class SGWeakPtr;
}; };
#endif #endif
+75
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
+103
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