weak_ptr made thread safe, shared->weak conversions, lightweight_mutex added.

[SVN r12786]
This commit is contained in:
Peter Dimov
2002-02-12 16:55:25 +00:00
parent cd8dea78e6
commit 1b69c14f45
8 changed files with 429 additions and 43 deletions
@@ -0,0 +1,49 @@
#ifndef BOOST_DETAIL_LIGHTWEIGHT_MUTEX_HPP_INCLUDED
#define BOOST_DETAIL_LIGHTWEIGHT_MUTEX_HPP_INCLUDED
#if _MSC_VER >= 1020
#pragma once
#endif
//
// boost/detail/lightweight_mutex.hpp - lightweight mutex
//
// Copyright (c) 2002 Peter Dimov and Multi Media Ltd.
//
// Permission to copy, use, modify, sell and distribute this software
// is granted provided this copyright notice appears in all copies.
// This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
// typedef <implementation-defined> boost::detail::lightweight_mutex;
//
// boost::detail::lightweight_mutex meets the Mutex concept requirements
// See http://www.boost.org/libs/thread/doc/mutex_concept.html#Mutex
//
// * Used by the smart pointer library
// * Performance oriented
// * Header-only implementation
// * Small memory footprint
// * Not a general purpose mutex, use boost::mutex, CRITICAL_SECTION or
// pthread_mutex instead.
// * Never spin in a tight lock/do-something/unlock loop, since
// lightweight_mutex does not guarantee fairness.
// * Never keep a lightweight_mutex locked for long periods.
//
#include <boost/config.hpp>
#ifndef BOOST_HAS_THREADS
# include <boost/detail/lwm_nop.hpp>
#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
# include <boost/detail/lwm_win32.hpp>
//#elif defined(linux) || defined(__linux) || defined(__linux__)
//# include <boost/detail/lwm_linux.hpp>
#elif defined(BOOST_HAS_PTHREADS)
# include <boost/detail/lwm_pthreads.hpp>
#else
# include <boost/detail/lwm_nop.hpp>
#endif
#endif // #ifndef BOOST_DETAIL_LIGHTWEIGHT_MUTEX_HPP_INCLUDED
+57
View File
@@ -0,0 +1,57 @@
#ifndef BOOST_DETAIL_LWM_NOP_HPP_INCLUDED
#define BOOST_DETAIL_LWM_NOP_HPP_INCLUDED
#if _MSC_VER >= 1020
#pragma once
#endif
//
// boost/detail/lwm_nop.hpp
//
// Copyright (c) 2002 Peter Dimov and Multi Media Ltd.
//
// Permission to copy, use, modify, sell and distribute this software
// is granted provided this copyright notice appears in all copies.
// This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
namespace boost
{
namespace detail
{
class lightweight_mutex
{
private:
lightweight_mutex(lightweight_mutex const &);
lightweight_mutex & operator=(lightweight_mutex const &);
public:
lightweight_mutex()
{
}
class scoped_lock
{
private:
scoped_lock(scoped_lock const &);
scoped_lock & operator=(scoped_lock const &);
public:
explicit scoped_lock(lightweight_mutex &)
{
}
};
};
} // namespace detail
} // namespace boost
#endif // #ifndef BOOST_DETAIL_LWM_NOP_HPP_INCLUDED
+78
View File
@@ -0,0 +1,78 @@
#ifndef BOOST_DETAIL_LWM_PTHREADS_HPP_INCLUDED
#define BOOST_DETAIL_LWM_PTHREADS_HPP_INCLUDED
#if _MSC_VER >= 1020
#pragma once
#endif
//
// boost/detail/lwm_pthreads.hpp
//
// Copyright (c) 2002 Peter Dimov and Multi Media Ltd.
//
// Permission to copy, use, modify, sell and distribute this software
// is granted provided this copyright notice appears in all copies.
// This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
#include <pthread.h>
namespace boost
{
namespace detail
{
class lightweight_mutex
{
private:
pthread_mutex_t m_;
lightweight_mutex(lightweight_mutex const &);
lightweight_mutex & operator=(lightweight_mutex const &);
public:
lightweight_mutex()
{
pthread_mutex_init(&m_, 0);
}
~lightweight_mutex()
{
pthread_mutex_destroy(&m_);
}
class scoped_lock;
friend class scoped_lock;
class scoped_lock
{
private:
pthread_mutex_t & m_;
scoped_lock(scoped_lock const &);
scoped_lock & operator=(scoped_lock const &);
public:
scoped_lock(lightweight_mutex & m): m_(m.m_)
{
pthread_mutex_lock(&m_);
}
~scoped_lock()
{
pthread_mutex_unlock(&m_);
}
};
};
} // namespace detail
} // namespace boost
#endif // #ifndef BOOST_DETAIL_LWM_PTHREADS_HPP_INCLUDED
+84
View File
@@ -0,0 +1,84 @@
#ifndef BOOST_DETAIL_LWM_WIN32_HPP_INCLUDED
#define BOOST_DETAIL_LWM_WIN32_HPP_INCLUDED
#if _MSC_VER >= 1020
#pragma once
#endif
//
// boost/detail/lwm_win32.hpp
//
// Copyright (c) 2002 Peter Dimov and Multi Media Ltd.
//
// Permission to copy, use, modify, sell and distribute this software
// is granted provided this copyright notice appears in all copies.
// This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
namespace boost
{
namespace detail
{
// Avoid #including <windows.h>
namespace win32
{
extern "C" __declspec(dllimport) long __stdcall InterlockedExchange(long volatile *, long);
extern "C" __declspec(dllimport) void __stdcall Sleep(unsigned long);
}
class lightweight_mutex
{
private:
long l_;
lightweight_mutex(lightweight_mutex const &);
lightweight_mutex & operator=(lightweight_mutex const &);
public:
lightweight_mutex(): l_(0)
{
}
class scoped_lock;
friend class scoped_lock;
class scoped_lock
{
private:
lightweight_mutex & m_;
scoped_lock(scoped_lock const &);
scoped_lock & operator=(scoped_lock const &);
public:
explicit scoped_lock(lightweight_mutex & m): m_(m)
{
while( win32::InterlockedExchange(&m_.l_, 1) ) win32::Sleep(0);
}
~scoped_lock()
{
win32::InterlockedExchange(&m_.l_, 0);
// Note: adding a win32::Sleep(0) here will make
// the mutex more fair and will increase the overall
// performance of the application substantially in
// high contention situations, but will penalize the
// low contention / single thread case up to 5x
}
};
};
} // namespace detail
} // namespace boost
#endif // #ifndef BOOST_DETAIL_LWM_WIN32_HPP_INCLUDED
+49 -11
View File
@@ -23,9 +23,10 @@
#endif
#include <boost/checked_delete.hpp>
#include <boost/detail/atomic_count.hpp>
#include <boost/detail/lightweight_mutex.hpp>
#include <functional> // for std::less
#include <functional> // for std::less
#include <exception> // for std::exception
namespace boost
{
@@ -33,11 +34,19 @@ namespace boost
namespace detail
{
class counted_base
class bad_weak_to_shared_cast: public std::exception
{
public:
typedef atomic_count count_type;
virtual char const * what() const throw()
{
return "bad_weak_to_shared_cast";
}
};
class counted_base
{
public:
// pre: initial_use_count <= initial_weak_count
@@ -63,20 +72,31 @@ public:
{
}
void add_ref() // nothrow
void add_ref()
{
lightweight_mutex::scoped_lock lock(mtx_);
if(use_count_ == 0) throw bad_weak_to_shared_cast();
++use_count_;
++weak_count_;
}
void release() // nothrow
{
if(--use_count_ == 0)
long new_use_count;
long new_weak_count;
{
lightweight_mutex::scoped_lock lock(mtx_);
new_use_count = --use_count_;
new_weak_count = --weak_count_;
}
if(new_use_count == 0)
{
dispose();
}
if(--weak_count_ == 0)
if(new_weak_count == 0)
{
// not a direct 'delete this', because the inlined
// release() may use a different heap manager
@@ -86,12 +106,20 @@ public:
void weak_add_ref() // nothrow
{
lightweight_mutex::scoped_lock lock(mtx_);
++weak_count_;
}
void weak_release() // nothrow
{
if(--weak_count_ == 0)
long new_weak_count;
{
lightweight_mutex::scoped_lock lock(mtx_);
new_weak_count = --weak_count_;
}
if(new_weak_count == 0)
{
self_deleter_(this);
}
@@ -99,6 +127,7 @@ public:
long use_count() const // nothrow
{
lightweight_mutex::scoped_lock lock(mtx_);
return use_count_;
}
@@ -114,9 +143,9 @@ private:
// inv: use_count_ <= weak_count_
count_type use_count_;
count_type weak_count_;
long use_count_;
long weak_count_;
mutable lightweight_mutex mtx_;
void (*self_deleter_) (counted_base *);
};
@@ -191,6 +220,8 @@ public:
pi_->add_ref();
}
explicit shared_count(weak_count const & r); // throws bad_weak_to_shared_cast when r.use_count() == 0
shared_count & operator= (shared_count const & r) // nothrow
{
counted_base * tmp = r.pi_;
@@ -235,6 +266,8 @@ private:
counted_base * pi_;
friend class shared_count;
public:
weak_count(): pi_(new counted_base(0, 1)) // can throw
@@ -299,6 +332,11 @@ public:
}
};
inline shared_count::shared_count(weak_count const & r): pi_(r.pi_)
{
pi_->add_ref();
}
} // namespace detail
} // namespace boost
+18
View File
@@ -97,6 +97,10 @@ public:
// generated copy constructor, assignment, destructor are fine
explicit shared_ptr(weak_ptr<T> const & r): px(r.px), pn(r.pn) // may throw
{
}
template<typename Y>
shared_ptr(shared_ptr<Y> const & r): px(r.px), pn(r.pn) // never throws
{
@@ -191,6 +195,20 @@ public:
return pn.use_count();
}
// implicit conversion to "bool"
typedef long (this_type::*bool_type)() const;
operator bool_type() const // never throws
{
return px == 0? 0: &this_type::use_count;
}
bool operator! () const // never throws
{
return px == 0;
}
void swap(shared_ptr<T> & other) // never throws
{
std::swap(px, other.px);
+38 -20
View File
@@ -30,6 +30,7 @@ private:
// Borland 5.5.1 specific workarounds
typedef weak_ptr<T> this_type;
typedef shared_ptr<T> shared_type;
public:
@@ -95,23 +96,32 @@ public:
this_type().swap(*this);
}
T * get() const // never throws
shared_type get() const // never throws
{
return use_count() == 0? 0: px;
// optimization: avoid throw overhead
if(use_count() == 0)
{
return shared_type();
}
try
{
return shared_type(*this);
}
catch(boost::detail::bad_weak_to_shared_cast const &)
{
return shared_type();
}
}
typename detail::shared_ptr_traits<T>::reference operator* () const // never throws
{
element_type * p = get();
BOOST_ASSERT(p != 0);
return *p;
}
// operator* has been removed; it's unsafe.
T * operator-> () const // never throws
// operator-> retained for convenience, since it's safe
// in its current form.
shared_type operator-> () const // may throw
{
element_type * p = get();
BOOST_ASSERT(p != 0);
return p;
return shared_type(*this);
}
long use_count() const // never throws
@@ -119,7 +129,21 @@ public:
return pn.use_count();
}
void swap(weak_ptr<T> & other) // never throws
// implicit conversion to "bool"
typedef long (this_type::*bool_type)() const;
operator bool_type() const // never throws
{
return use_count() == 0? 0: &this_type::use_count;
}
bool operator! () const // never throws
{
return use_count() == 0;
}
void swap(this_type & other) // never throws
{
std::swap(px, other.px);
pn.swap(other.pn);
@@ -138,6 +162,7 @@ public:
private:
template<typename Y> friend class weak_ptr;
template<typename Y> friend class shared_ptr;
#endif
@@ -198,13 +223,6 @@ template<typename T, typename U> weak_ptr<T> shared_polymorphic_downcast(weak_pt
return shared_static_cast<T>(r);
}
// get_pointer() enables boost::mem_fn to recognize weak_ptr
template<class T> inline T * get_pointer(weak_ptr<T> const & p)
{
return p.get();
}
} // namespace boost
#ifdef BOOST_MSVC