forked from boostorg/smart_ptr
weak_ptr made thread safe, shared->weak conversions, lightweight_mutex added.
[SVN r12786]
This commit is contained in:
1 parent
cd8dea78e6
commit
1b69c14f45
8 files changed
+429
-43
No files matched your search
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
Reference in new issue
Block a user