// Distributed under the Boost Software License, Version 1.0. (See | |
// accompanying file LICENSE_1_0.txt or copy at | |
// http://www.boost.org/LICENSE_1_0.txt) | |
// (C) Copyright 2007 Anthony Williams | |
#ifndef BOOST_THREAD_LOCKS_HPP | |
#define BOOST_THREAD_LOCKS_HPP | |
#include <boost/thread/detail/config.hpp> | |
#include <boost/thread/exceptions.hpp> | |
#include <boost/thread/detail/move.hpp> | |
#include <algorithm> | |
#include <iterator> | |
#include <boost/thread/thread_time.hpp> | |
#include <boost/detail/workaround.hpp> | |
#include <boost/type_traits/is_class.hpp> | |
#include <boost/config/abi_prefix.hpp> | |
namespace boost | |
{ | |
struct xtime; | |
#if defined(BOOST_NO_SFINAE) || \ | |
BOOST_WORKAROUND(__IBMCPP__, BOOST_TESTED_AT(600)) || \ | |
BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) | |
#define BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES | |
#endif | |
#ifndef BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES | |
namespace detail | |
{ | |
#define BOOST_DEFINE_HAS_MEMBER_CALLED(member_name) \ | |
template<typename T, bool=boost::is_class<T>::value> \ | |
struct has_member_called_##member_name \ | |
{ \ | |
BOOST_STATIC_CONSTANT(bool, value=false); \ | |
}; \ | |
\ | |
template<typename T> \ | |
struct has_member_called_##member_name<T,true> \ | |
{ \ | |
typedef char true_type; \ | |
struct false_type \ | |
{ \ | |
true_type dummy[2]; \ | |
}; \ | |
\ | |
struct fallback { int member_name; }; \ | |
struct derived: \ | |
T, fallback \ | |
{ \ | |
derived(); \ | |
}; \ | |
\ | |
template<int fallback::*> struct tester; \ | |
\ | |
template<typename U> \ | |
static false_type has_member(tester<&U::member_name>*); \ | |
template<typename U> \ | |
static true_type has_member(...); \ | |
\ | |
BOOST_STATIC_CONSTANT( \ | |
bool, value=sizeof(has_member<derived>(0))==sizeof(true_type)); \ | |
} | |
BOOST_DEFINE_HAS_MEMBER_CALLED(lock); | |
BOOST_DEFINE_HAS_MEMBER_CALLED(unlock); | |
BOOST_DEFINE_HAS_MEMBER_CALLED(try_lock); | |
template<typename T,bool=has_member_called_lock<T>::value > | |
struct has_member_lock | |
{ | |
BOOST_STATIC_CONSTANT(bool, value=false); | |
}; | |
template<typename T> | |
struct has_member_lock<T,true> | |
{ | |
typedef char true_type; | |
struct false_type | |
{ | |
true_type dummy[2]; | |
}; | |
template<typename U,typename V> | |
static true_type has_member(V (U::*)()); | |
template<typename U> | |
static false_type has_member(U); | |
BOOST_STATIC_CONSTANT( | |
bool,value=sizeof(has_member_lock<T>::has_member(&T::lock))==sizeof(true_type)); | |
}; | |
template<typename T,bool=has_member_called_unlock<T>::value > | |
struct has_member_unlock | |
{ | |
BOOST_STATIC_CONSTANT(bool, value=false); | |
}; | |
template<typename T> | |
struct has_member_unlock<T,true> | |
{ | |
typedef char true_type; | |
struct false_type | |
{ | |
true_type dummy[2]; | |
}; | |
template<typename U,typename V> | |
static true_type has_member(V (U::*)()); | |
template<typename U> | |
static false_type has_member(U); | |
BOOST_STATIC_CONSTANT( | |
bool,value=sizeof(has_member_unlock<T>::has_member(&T::unlock))==sizeof(true_type)); | |
}; | |
template<typename T,bool=has_member_called_try_lock<T>::value > | |
struct has_member_try_lock | |
{ | |
BOOST_STATIC_CONSTANT(bool, value=false); | |
}; | |
template<typename T> | |
struct has_member_try_lock<T,true> | |
{ | |
typedef char true_type; | |
struct false_type | |
{ | |
true_type dummy[2]; | |
}; | |
template<typename U> | |
static true_type has_member(bool (U::*)()); | |
template<typename U> | |
static false_type has_member(U); | |
BOOST_STATIC_CONSTANT( | |
bool,value=sizeof(has_member_try_lock<T>::has_member(&T::try_lock))==sizeof(true_type)); | |
}; | |
} | |
template<typename T> | |
struct is_mutex_type | |
{ | |
BOOST_STATIC_CONSTANT(bool, value = detail::has_member_lock<T>::value && | |
detail::has_member_unlock<T>::value && | |
detail::has_member_try_lock<T>::value); | |
}; | |
#else | |
template<typename T> | |
struct is_mutex_type | |
{ | |
BOOST_STATIC_CONSTANT(bool, value = false); | |
}; | |
#endif | |
struct defer_lock_t | |
{}; | |
struct try_to_lock_t | |
{}; | |
struct adopt_lock_t | |
{}; | |
const defer_lock_t defer_lock={}; | |
const try_to_lock_t try_to_lock={}; | |
const adopt_lock_t adopt_lock={}; | |
template<typename Mutex> | |
class shared_lock; | |
template<typename Mutex> | |
class upgrade_lock; | |
template<typename Mutex> | |
class unique_lock; | |
namespace detail | |
{ | |
template<typename Mutex> | |
class try_lock_wrapper; | |
} | |
#ifdef BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES | |
template<typename T> | |
struct is_mutex_type<unique_lock<T> > | |
{ | |
BOOST_STATIC_CONSTANT(bool, value = true); | |
}; | |
template<typename T> | |
struct is_mutex_type<shared_lock<T> > | |
{ | |
BOOST_STATIC_CONSTANT(bool, value = true); | |
}; | |
template<typename T> | |
struct is_mutex_type<upgrade_lock<T> > | |
{ | |
BOOST_STATIC_CONSTANT(bool, value = true); | |
}; | |
template<typename T> | |
struct is_mutex_type<detail::try_lock_wrapper<T> > | |
{ | |
BOOST_STATIC_CONSTANT(bool, value = true); | |
}; | |
class mutex; | |
class timed_mutex; | |
class recursive_mutex; | |
class recursive_timed_mutex; | |
class shared_mutex; | |
template<> | |
struct is_mutex_type<mutex> | |
{ | |
BOOST_STATIC_CONSTANT(bool, value = true); | |
}; | |
template<> | |
struct is_mutex_type<timed_mutex> | |
{ | |
BOOST_STATIC_CONSTANT(bool, value = true); | |
}; | |
template<> | |
struct is_mutex_type<recursive_mutex> | |
{ | |
BOOST_STATIC_CONSTANT(bool, value = true); | |
}; | |
template<> | |
struct is_mutex_type<recursive_timed_mutex> | |
{ | |
BOOST_STATIC_CONSTANT(bool, value = true); | |
}; | |
template<> | |
struct is_mutex_type<shared_mutex> | |
{ | |
BOOST_STATIC_CONSTANT(bool, value = true); | |
}; | |
#endif | |
template<typename Mutex> | |
class lock_guard | |
{ | |
private: | |
Mutex& m; | |
explicit lock_guard(lock_guard&); | |
lock_guard& operator=(lock_guard&); | |
public: | |
explicit lock_guard(Mutex& m_): | |
m(m_) | |
{ | |
m.lock(); | |
} | |
lock_guard(Mutex& m_,adopt_lock_t): | |
m(m_) | |
{} | |
~lock_guard() | |
{ | |
m.unlock(); | |
} | |
}; | |
template<typename Mutex> | |
class unique_lock | |
{ | |
private: | |
Mutex* m; | |
bool is_locked; | |
unique_lock(unique_lock&); | |
explicit unique_lock(upgrade_lock<Mutex>&); | |
unique_lock& operator=(unique_lock&); | |
unique_lock& operator=(upgrade_lock<Mutex>& other); | |
public: | |
#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100) | |
unique_lock(const volatile unique_lock&); | |
#endif | |
unique_lock(): | |
m(0),is_locked(false) | |
{} | |
explicit unique_lock(Mutex& m_): | |
m(&m_),is_locked(false) | |
{ | |
lock(); | |
} | |
unique_lock(Mutex& m_,adopt_lock_t): | |
m(&m_),is_locked(true) | |
{} | |
unique_lock(Mutex& m_,defer_lock_t): | |
m(&m_),is_locked(false) | |
{} | |
unique_lock(Mutex& m_,try_to_lock_t): | |
m(&m_),is_locked(false) | |
{ | |
try_lock(); | |
} | |
template<typename TimeDuration> | |
unique_lock(Mutex& m_,TimeDuration const& target_time): | |
m(&m_),is_locked(false) | |
{ | |
timed_lock(target_time); | |
} | |
unique_lock(Mutex& m_,system_time const& target_time): | |
m(&m_),is_locked(false) | |
{ | |
timed_lock(target_time); | |
} | |
#ifndef BOOST_NO_RVALUE_REFERENCES | |
unique_lock(unique_lock&& other): | |
m(other.m),is_locked(other.is_locked) | |
{ | |
other.is_locked=false; | |
other.m=0; | |
} | |
explicit unique_lock(upgrade_lock<Mutex>&& other); | |
unique_lock<Mutex>&& move() | |
{ | |
return static_cast<unique_lock<Mutex>&&>(*this); | |
} | |
unique_lock& operator=(unique_lock&& other) | |
{ | |
unique_lock temp(other.move()); | |
swap(temp); | |
return *this; | |
} | |
unique_lock& operator=(upgrade_lock<Mutex>&& other) | |
{ | |
unique_lock temp(other.move()); | |
swap(temp); | |
return *this; | |
} | |
void swap(unique_lock&& other) | |
{ | |
std::swap(m,other.m); | |
std::swap(is_locked,other.is_locked); | |
} | |
#else | |
unique_lock(detail::thread_move_t<unique_lock<Mutex> > other): | |
m(other->m),is_locked(other->is_locked) | |
{ | |
other->is_locked=false; | |
other->m=0; | |
} | |
unique_lock(detail::thread_move_t<upgrade_lock<Mutex> > other); | |
operator detail::thread_move_t<unique_lock<Mutex> >() | |
{ | |
return move(); | |
} | |
detail::thread_move_t<unique_lock<Mutex> > move() | |
{ | |
return detail::thread_move_t<unique_lock<Mutex> >(*this); | |
} | |
#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100) | |
unique_lock& operator=(unique_lock<Mutex> other) | |
{ | |
swap(other); | |
return *this; | |
} | |
#else | |
unique_lock& operator=(detail::thread_move_t<unique_lock<Mutex> > other) | |
{ | |
unique_lock temp(other); | |
swap(temp); | |
return *this; | |
} | |
#endif | |
unique_lock& operator=(detail::thread_move_t<upgrade_lock<Mutex> > other) | |
{ | |
unique_lock temp(other); | |
swap(temp); | |
return *this; | |
} | |
void swap(detail::thread_move_t<unique_lock<Mutex> > other) | |
{ | |
std::swap(m,other->m); | |
std::swap(is_locked,other->is_locked); | |
} | |
#endif | |
void swap(unique_lock& other) | |
{ | |
std::swap(m,other.m); | |
std::swap(is_locked,other.is_locked); | |
} | |
~unique_lock() | |
{ | |
if(owns_lock()) | |
{ | |
m->unlock(); | |
} | |
} | |
void lock() | |
{ | |
if(owns_lock()) | |
{ | |
boost::throw_exception(boost::lock_error()); | |
} | |
m->lock(); | |
is_locked=true; | |
} | |
bool try_lock() | |
{ | |
if(owns_lock()) | |
{ | |
boost::throw_exception(boost::lock_error()); | |
} | |
is_locked=m->try_lock(); | |
return is_locked; | |
} | |
template<typename TimeDuration> | |
bool timed_lock(TimeDuration const& relative_time) | |
{ | |
is_locked=m->timed_lock(relative_time); | |
return is_locked; | |
} | |
bool timed_lock(::boost::system_time const& absolute_time) | |
{ | |
is_locked=m->timed_lock(absolute_time); | |
return is_locked; | |
} | |
bool timed_lock(::boost::xtime const& absolute_time) | |
{ | |
is_locked=m->timed_lock(absolute_time); | |
return is_locked; | |
} | |
void unlock() | |
{ | |
if(!owns_lock()) | |
{ | |
boost::throw_exception(boost::lock_error()); | |
} | |
m->unlock(); | |
is_locked=false; | |
} | |
typedef void (unique_lock::*bool_type)(); | |
operator bool_type() const | |
{ | |
return is_locked?&unique_lock::lock:0; | |
} | |
bool operator!() const | |
{ | |
return !owns_lock(); | |
} | |
bool owns_lock() const | |
{ | |
return is_locked; | |
} | |
Mutex* mutex() const | |
{ | |
return m; | |
} | |
Mutex* release() | |
{ | |
Mutex* const res=m; | |
m=0; | |
is_locked=false; | |
return res; | |
} | |
friend class shared_lock<Mutex>; | |
friend class upgrade_lock<Mutex>; | |
}; | |
#ifndef BOOST_NO_RVALUE_REFERENCES | |
template<typename Mutex> | |
void swap(unique_lock<Mutex>&& lhs,unique_lock<Mutex>&& rhs) | |
{ | |
lhs.swap(rhs); | |
} | |
template<typename Mutex> | |
inline upgrade_lock<Mutex>&& move(upgrade_lock<Mutex>&& ul) | |
{ | |
return static_cast<upgrade_lock<Mutex>&&>(ul); | |
} | |
template<typename Mutex> | |
inline upgrade_lock<Mutex>&& move(upgrade_lock<Mutex>& ul) | |
{ | |
return static_cast<upgrade_lock<Mutex>&&>(ul); | |
} | |
#endif | |
template<typename Mutex> | |
void swap(unique_lock<Mutex>& lhs,unique_lock<Mutex>& rhs) | |
{ | |
lhs.swap(rhs); | |
} | |
#ifndef BOOST_NO_RVALUE_REFERENCES | |
template<typename Mutex> | |
inline unique_lock<Mutex>&& move(unique_lock<Mutex>&& ul) | |
{ | |
return static_cast<unique_lock<Mutex>&&>(ul); | |
} | |
template<typename Mutex> | |
inline unique_lock<Mutex>&& move(unique_lock<Mutex>& ul) | |
{ | |
return static_cast<unique_lock<Mutex>&&>(ul); | |
} | |
#endif | |
template<typename Mutex> | |
class shared_lock | |
{ | |
protected: | |
Mutex* m; | |
bool is_locked; | |
private: | |
explicit shared_lock(shared_lock&); | |
shared_lock& operator=(shared_lock&); | |
public: | |
shared_lock(): | |
m(0),is_locked(false) | |
{} | |
explicit shared_lock(Mutex& m_): | |
m(&m_),is_locked(false) | |
{ | |
lock(); | |
} | |
shared_lock(Mutex& m_,adopt_lock_t): | |
m(&m_),is_locked(true) | |
{} | |
shared_lock(Mutex& m_,defer_lock_t): | |
m(&m_),is_locked(false) | |
{} | |
shared_lock(Mutex& m_,try_to_lock_t): | |
m(&m_),is_locked(false) | |
{ | |
try_lock(); | |
} | |
shared_lock(Mutex& m_,system_time const& target_time): | |
m(&m_),is_locked(false) | |
{ | |
timed_lock(target_time); | |
} | |
shared_lock(detail::thread_move_t<shared_lock<Mutex> > other): | |
m(other->m),is_locked(other->is_locked) | |
{ | |
other->is_locked=false; | |
other->m=0; | |
} | |
shared_lock(detail::thread_move_t<unique_lock<Mutex> > other): | |
m(other->m),is_locked(other->is_locked) | |
{ | |
if(is_locked) | |
{ | |
m->unlock_and_lock_shared(); | |
} | |
other->is_locked=false; | |
other->m=0; | |
} | |
shared_lock(detail::thread_move_t<upgrade_lock<Mutex> > other): | |
m(other->m),is_locked(other->is_locked) | |
{ | |
if(is_locked) | |
{ | |
m->unlock_upgrade_and_lock_shared(); | |
} | |
other->is_locked=false; | |
other->m=0; | |
} | |
operator detail::thread_move_t<shared_lock<Mutex> >() | |
{ | |
return move(); | |
} | |
detail::thread_move_t<shared_lock<Mutex> > move() | |
{ | |
return detail::thread_move_t<shared_lock<Mutex> >(*this); | |
} | |
shared_lock& operator=(detail::thread_move_t<shared_lock<Mutex> > other) | |
{ | |
shared_lock temp(other); | |
swap(temp); | |
return *this; | |
} | |
shared_lock& operator=(detail::thread_move_t<unique_lock<Mutex> > other) | |
{ | |
shared_lock temp(other); | |
swap(temp); | |
return *this; | |
} | |
shared_lock& operator=(detail::thread_move_t<upgrade_lock<Mutex> > other) | |
{ | |
shared_lock temp(other); | |
swap(temp); | |
return *this; | |
} | |
#ifndef BOOST_NO_RVALUE_REFERENCES | |
void swap(shared_lock&& other) | |
{ | |
std::swap(m,other.m); | |
std::swap(is_locked,other.is_locked); | |
} | |
#else | |
void swap(boost::detail::thread_move_t<shared_lock<Mutex> > other) | |
{ | |
std::swap(m,other->m); | |
std::swap(is_locked,other->is_locked); | |
} | |
#endif | |
void swap(shared_lock& other) | |
{ | |
std::swap(m,other.m); | |
std::swap(is_locked,other.is_locked); | |
} | |
Mutex* mutex() const | |
{ | |
return m; | |
} | |
~shared_lock() | |
{ | |
if(owns_lock()) | |
{ | |
m->unlock_shared(); | |
} | |
} | |
void lock() | |
{ | |
if(owns_lock()) | |
{ | |
boost::throw_exception(boost::lock_error()); | |
} | |
m->lock_shared(); | |
is_locked=true; | |
} | |
bool try_lock() | |
{ | |
if(owns_lock()) | |
{ | |
boost::throw_exception(boost::lock_error()); | |
} | |
is_locked=m->try_lock_shared(); | |
return is_locked; | |
} | |
bool timed_lock(boost::system_time const& target_time) | |
{ | |
if(owns_lock()) | |
{ | |
boost::throw_exception(boost::lock_error()); | |
} | |
is_locked=m->timed_lock_shared(target_time); | |
return is_locked; | |
} | |
template<typename Duration> | |
bool timed_lock(Duration const& target_time) | |
{ | |
if(owns_lock()) | |
{ | |
boost::throw_exception(boost::lock_error()); | |
} | |
is_locked=m->timed_lock_shared(target_time); | |
return is_locked; | |
} | |
void unlock() | |
{ | |
if(!owns_lock()) | |
{ | |
boost::throw_exception(boost::lock_error()); | |
} | |
m->unlock_shared(); | |
is_locked=false; | |
} | |
typedef void (shared_lock<Mutex>::*bool_type)(); | |
operator bool_type() const | |
{ | |
return is_locked?&shared_lock::lock:0; | |
} | |
bool operator!() const | |
{ | |
return !owns_lock(); | |
} | |
bool owns_lock() const | |
{ | |
return is_locked; | |
} | |
}; | |
#ifndef BOOST_NO_RVALUE_REFERENCES | |
template<typename Mutex> | |
void swap(shared_lock<Mutex>&& lhs,shared_lock<Mutex>&& rhs) | |
{ | |
lhs.swap(rhs); | |
} | |
#else | |
template<typename Mutex> | |
void swap(shared_lock<Mutex>& lhs,shared_lock<Mutex>& rhs) | |
{ | |
lhs.swap(rhs); | |
} | |
#endif | |
template<typename Mutex> | |
class upgrade_lock | |
{ | |
protected: | |
Mutex* m; | |
bool is_locked; | |
private: | |
explicit upgrade_lock(upgrade_lock&); | |
upgrade_lock& operator=(upgrade_lock&); | |
public: | |
upgrade_lock(): | |
m(0),is_locked(false) | |
{} | |
explicit upgrade_lock(Mutex& m_): | |
m(&m_),is_locked(false) | |
{ | |
lock(); | |
} | |
upgrade_lock(Mutex& m_,adopt_lock_t): | |
m(&m_),is_locked(true) | |
{} | |
upgrade_lock(Mutex& m_,defer_lock_t): | |
m(&m_),is_locked(false) | |
{} | |
upgrade_lock(Mutex& m_,try_to_lock_t): | |
m(&m_),is_locked(false) | |
{ | |
try_lock(); | |
} | |
#ifdef BOOST_HAS_RVALUE_REFS | |
upgrade_lock(upgrade_lock<Mutex>&& other): | |
m(other.m),is_locked(other.is_locked) | |
{ | |
other.is_locked=false; | |
other.m=0; | |
} | |
upgrade_lock(unique_lock<Mutex>&& other): | |
m(other.m),is_locked(other.is_locked) | |
{ | |
if(is_locked) | |
{ | |
m->unlock_and_lock_upgrade(); | |
} | |
other.is_locked=false; | |
other.m=0; | |
} | |
upgrade_lock& operator=(upgrade_lock<Mutex>&& other) | |
{ | |
upgrade_lock temp(static_cast<upgrade_lock<Mutex>&&>(other)); | |
swap(temp); | |
return *this; | |
} | |
upgrade_lock& operator=(unique_lock<Mutex>&& other) | |
{ | |
upgrade_lock temp(static_cast<unique_lock<Mutex>&&>(other)); | |
swap(temp); | |
return *this; | |
} | |
#else | |
upgrade_lock(detail::thread_move_t<upgrade_lock<Mutex> > other): | |
m(other->m),is_locked(other->is_locked) | |
{ | |
other->is_locked=false; | |
other->m=0; | |
} | |
upgrade_lock(detail::thread_move_t<unique_lock<Mutex> > other): | |
m(other->m),is_locked(other->is_locked) | |
{ | |
if(is_locked) | |
{ | |
m->unlock_and_lock_upgrade(); | |
} | |
other->is_locked=false; | |
other->m=0; | |
} | |
operator detail::thread_move_t<upgrade_lock<Mutex> >() | |
{ | |
return move(); | |
} | |
detail::thread_move_t<upgrade_lock<Mutex> > move() | |
{ | |
return detail::thread_move_t<upgrade_lock<Mutex> >(*this); | |
} | |
upgrade_lock& operator=(detail::thread_move_t<upgrade_lock<Mutex> > other) | |
{ | |
upgrade_lock temp(other); | |
swap(temp); | |
return *this; | |
} | |
upgrade_lock& operator=(detail::thread_move_t<unique_lock<Mutex> > other) | |
{ | |
upgrade_lock temp(other); | |
swap(temp); | |
return *this; | |
} | |
#endif | |
void swap(upgrade_lock& other) | |
{ | |
std::swap(m,other.m); | |
std::swap(is_locked,other.is_locked); | |
} | |
~upgrade_lock() | |
{ | |
if(owns_lock()) | |
{ | |
m->unlock_upgrade(); | |
} | |
} | |
void lock() | |
{ | |
if(owns_lock()) | |
{ | |
boost::throw_exception(boost::lock_error()); | |
} | |
m->lock_upgrade(); | |
is_locked=true; | |
} | |
bool try_lock() | |
{ | |
if(owns_lock()) | |
{ | |
boost::throw_exception(boost::lock_error()); | |
} | |
is_locked=m->try_lock_upgrade(); | |
return is_locked; | |
} | |
void unlock() | |
{ | |
if(!owns_lock()) | |
{ | |
boost::throw_exception(boost::lock_error()); | |
} | |
m->unlock_upgrade(); | |
is_locked=false; | |
} | |
typedef void (upgrade_lock::*bool_type)(); | |
operator bool_type() const | |
{ | |
return is_locked?&upgrade_lock::lock:0; | |
} | |
bool operator!() const | |
{ | |
return !owns_lock(); | |
} | |
bool owns_lock() const | |
{ | |
return is_locked; | |
} | |
friend class shared_lock<Mutex>; | |
friend class unique_lock<Mutex>; | |
}; | |
#ifndef BOOST_NO_RVALUE_REFERENCES | |
template<typename Mutex> | |
unique_lock<Mutex>::unique_lock(upgrade_lock<Mutex>&& other): | |
m(other.m),is_locked(other.is_locked) | |
{ | |
other.is_locked=false; | |
if(is_locked) | |
{ | |
m->unlock_upgrade_and_lock(); | |
} | |
} | |
#else | |
template<typename Mutex> | |
unique_lock<Mutex>::unique_lock(detail::thread_move_t<upgrade_lock<Mutex> > other): | |
m(other->m),is_locked(other->is_locked) | |
{ | |
other->is_locked=false; | |
if(is_locked) | |
{ | |
m->unlock_upgrade_and_lock(); | |
} | |
} | |
#endif | |
template <class Mutex> | |
class upgrade_to_unique_lock | |
{ | |
private: | |
upgrade_lock<Mutex>* source; | |
unique_lock<Mutex> exclusive; | |
explicit upgrade_to_unique_lock(upgrade_to_unique_lock&); | |
upgrade_to_unique_lock& operator=(upgrade_to_unique_lock&); | |
public: | |
explicit upgrade_to_unique_lock(upgrade_lock<Mutex>& m_): | |
source(&m_),exclusive(move(*source)) | |
{} | |
~upgrade_to_unique_lock() | |
{ | |
if(source) | |
{ | |
*source=move(exclusive); | |
} | |
} | |
#ifdef BOOST_HAS_RVALUE_REFS | |
upgrade_to_unique_lock(upgrade_to_unique_lock<Mutex>&& other): | |
source(other.source),exclusive(move(other.exclusive)) | |
{ | |
other.source=0; | |
} | |
upgrade_to_unique_lock& operator=(upgrade_to_unique_lock<Mutex>&& other) | |
{ | |
upgrade_to_unique_lock temp(other); | |
swap(temp); | |
return *this; | |
} | |
#else | |
upgrade_to_unique_lock(detail::thread_move_t<upgrade_to_unique_lock<Mutex> > other): | |
source(other->source),exclusive(move(other->exclusive)) | |
{ | |
other->source=0; | |
} | |
upgrade_to_unique_lock& operator=(detail::thread_move_t<upgrade_to_unique_lock<Mutex> > other) | |
{ | |
upgrade_to_unique_lock temp(other); | |
swap(temp); | |
return *this; | |
} | |
#endif | |
void swap(upgrade_to_unique_lock& other) | |
{ | |
std::swap(source,other.source); | |
exclusive.swap(other.exclusive); | |
} | |
typedef void (upgrade_to_unique_lock::*bool_type)(upgrade_to_unique_lock&); | |
operator bool_type() const | |
{ | |
return exclusive.owns_lock()?&upgrade_to_unique_lock::swap:0; | |
} | |
bool operator!() const | |
{ | |
return !owns_lock(); | |
} | |
bool owns_lock() const | |
{ | |
return exclusive.owns_lock(); | |
} | |
}; | |
namespace detail | |
{ | |
template<typename Mutex> | |
class try_lock_wrapper: | |
private unique_lock<Mutex> | |
{ | |
typedef unique_lock<Mutex> base; | |
public: | |
try_lock_wrapper() | |
{} | |
explicit try_lock_wrapper(Mutex& m): | |
base(m,try_to_lock) | |
{} | |
try_lock_wrapper(Mutex& m_,adopt_lock_t): | |
base(m_,adopt_lock) | |
{} | |
try_lock_wrapper(Mutex& m_,defer_lock_t): | |
base(m_,defer_lock) | |
{} | |
try_lock_wrapper(Mutex& m_,try_to_lock_t): | |
base(m_,try_to_lock) | |
{} | |
#ifndef BOOST_NO_RVALUE_REFERENCES | |
try_lock_wrapper(try_lock_wrapper&& other): | |
base(other.move()) | |
{} | |
try_lock_wrapper&& move() | |
{ | |
return static_cast<try_lock_wrapper&&>(*this); | |
} | |
try_lock_wrapper& operator=(try_lock_wrapper<Mutex>&& other) | |
{ | |
try_lock_wrapper temp(other.move()); | |
swap(temp); | |
return *this; | |
} | |
void swap(try_lock_wrapper&& other) | |
{ | |
base::swap(other); | |
} | |
#else | |
try_lock_wrapper(detail::thread_move_t<try_lock_wrapper<Mutex> > other): | |
base(detail::thread_move_t<base>(*other)) | |
{} | |
operator detail::thread_move_t<try_lock_wrapper<Mutex> >() | |
{ | |
return move(); | |
} | |
detail::thread_move_t<try_lock_wrapper<Mutex> > move() | |
{ | |
return detail::thread_move_t<try_lock_wrapper<Mutex> >(*this); | |
} | |
try_lock_wrapper& operator=(detail::thread_move_t<try_lock_wrapper<Mutex> > other) | |
{ | |
try_lock_wrapper temp(other); | |
swap(temp); | |
return *this; | |
} | |
void swap(detail::thread_move_t<try_lock_wrapper<Mutex> > other) | |
{ | |
base::swap(*other); | |
} | |
#endif | |
void swap(try_lock_wrapper& other) | |
{ | |
base::swap(other); | |
} | |
void lock() | |
{ | |
base::lock(); | |
} | |
bool try_lock() | |
{ | |
return base::try_lock(); | |
} | |
void unlock() | |
{ | |
base::unlock(); | |
} | |
bool owns_lock() const | |
{ | |
return base::owns_lock(); | |
} | |
Mutex* mutex() const | |
{ | |
return base::mutex(); | |
} | |
Mutex* release() | |
{ | |
return base::release(); | |
} | |
bool operator!() const | |
{ | |
return !this->owns_lock(); | |
} | |
typedef typename base::bool_type bool_type; | |
operator bool_type() const | |
{ | |
return base::operator bool_type(); | |
} | |
}; | |
#ifndef BOOST_NO_RVALUE_REFERENCES | |
template<typename Mutex> | |
void swap(try_lock_wrapper<Mutex>&& lhs,try_lock_wrapper<Mutex>&& rhs) | |
{ | |
lhs.swap(rhs); | |
} | |
#else | |
template<typename Mutex> | |
void swap(try_lock_wrapper<Mutex>& lhs,try_lock_wrapper<Mutex>& rhs) | |
{ | |
lhs.swap(rhs); | |
} | |
#endif | |
template<typename MutexType1,typename MutexType2> | |
unsigned try_lock_internal(MutexType1& m1,MutexType2& m2) | |
{ | |
boost::unique_lock<MutexType1> l1(m1,boost::try_to_lock); | |
if(!l1) | |
{ | |
return 1; | |
} | |
if(!m2.try_lock()) | |
{ | |
return 2; | |
} | |
l1.release(); | |
return 0; | |
} | |
template<typename MutexType1,typename MutexType2,typename MutexType3> | |
unsigned try_lock_internal(MutexType1& m1,MutexType2& m2,MutexType3& m3) | |
{ | |
boost::unique_lock<MutexType1> l1(m1,boost::try_to_lock); | |
if(!l1) | |
{ | |
return 1; | |
} | |
if(unsigned const failed_lock=try_lock_internal(m2,m3)) | |
{ | |
return failed_lock+1; | |
} | |
l1.release(); | |
return 0; | |
} | |
template<typename MutexType1,typename MutexType2,typename MutexType3, | |
typename MutexType4> | |
unsigned try_lock_internal(MutexType1& m1,MutexType2& m2,MutexType3& m3, | |
MutexType4& m4) | |
{ | |
boost::unique_lock<MutexType1> l1(m1,boost::try_to_lock); | |
if(!l1) | |
{ | |
return 1; | |
} | |
if(unsigned const failed_lock=try_lock_internal(m2,m3,m4)) | |
{ | |
return failed_lock+1; | |
} | |
l1.release(); | |
return 0; | |
} | |
template<typename MutexType1,typename MutexType2,typename MutexType3, | |
typename MutexType4,typename MutexType5> | |
unsigned try_lock_internal(MutexType1& m1,MutexType2& m2,MutexType3& m3, | |
MutexType4& m4,MutexType5& m5) | |
{ | |
boost::unique_lock<MutexType1> l1(m1,boost::try_to_lock); | |
if(!l1) | |
{ | |
return 1; | |
} | |
if(unsigned const failed_lock=try_lock_internal(m2,m3,m4,m5)) | |
{ | |
return failed_lock+1; | |
} | |
l1.release(); | |
return 0; | |
} | |
template<typename MutexType1,typename MutexType2> | |
unsigned lock_helper(MutexType1& m1,MutexType2& m2) | |
{ | |
boost::unique_lock<MutexType1> l1(m1); | |
if(!m2.try_lock()) | |
{ | |
return 1; | |
} | |
l1.release(); | |
return 0; | |
} | |
template<typename MutexType1,typename MutexType2,typename MutexType3> | |
unsigned lock_helper(MutexType1& m1,MutexType2& m2,MutexType3& m3) | |
{ | |
boost::unique_lock<MutexType1> l1(m1); | |
if(unsigned const failed_lock=try_lock_internal(m2,m3)) | |
{ | |
return failed_lock; | |
} | |
l1.release(); | |
return 0; | |
} | |
template<typename MutexType1,typename MutexType2,typename MutexType3, | |
typename MutexType4> | |
unsigned lock_helper(MutexType1& m1,MutexType2& m2,MutexType3& m3, | |
MutexType4& m4) | |
{ | |
boost::unique_lock<MutexType1> l1(m1); | |
if(unsigned const failed_lock=try_lock_internal(m2,m3,m4)) | |
{ | |
return failed_lock; | |
} | |
l1.release(); | |
return 0; | |
} | |
template<typename MutexType1,typename MutexType2,typename MutexType3, | |
typename MutexType4,typename MutexType5> | |
unsigned lock_helper(MutexType1& m1,MutexType2& m2,MutexType3& m3, | |
MutexType4& m4,MutexType5& m5) | |
{ | |
boost::unique_lock<MutexType1> l1(m1); | |
if(unsigned const failed_lock=try_lock_internal(m2,m3,m4,m5)) | |
{ | |
return failed_lock; | |
} | |
l1.release(); | |
return 0; | |
} | |
} | |
namespace detail | |
{ | |
template<bool x> | |
struct is_mutex_type_wrapper | |
{}; | |
template<typename MutexType1,typename MutexType2> | |
void lock_impl(MutexType1& m1,MutexType2& m2,is_mutex_type_wrapper<true>) | |
{ | |
unsigned const lock_count=2; | |
unsigned lock_first=0; | |
for(;;) | |
{ | |
switch(lock_first) | |
{ | |
case 0: | |
lock_first=detail::lock_helper(m1,m2); | |
if(!lock_first) | |
return; | |
break; | |
case 1: | |
lock_first=detail::lock_helper(m2,m1); | |
if(!lock_first) | |
return; | |
lock_first=(lock_first+1)%lock_count; | |
break; | |
} | |
} | |
} | |
template<typename Iterator> | |
void lock_impl(Iterator begin,Iterator end,is_mutex_type_wrapper<false>); | |
} | |
template<typename MutexType1,typename MutexType2> | |
void lock(MutexType1& m1,MutexType2& m2) | |
{ | |
detail::lock_impl(m1,m2,detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>()); | |
} | |
template<typename MutexType1,typename MutexType2> | |
void lock(const MutexType1& m1,MutexType2& m2) | |
{ | |
detail::lock_impl(m1,m2,detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>()); | |
} | |
template<typename MutexType1,typename MutexType2> | |
void lock(MutexType1& m1,const MutexType2& m2) | |
{ | |
detail::lock_impl(m1,m2,detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>()); | |
} | |
template<typename MutexType1,typename MutexType2> | |
void lock(const MutexType1& m1,const MutexType2& m2) | |
{ | |
detail::lock_impl(m1,m2,detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>()); | |
} | |
template<typename MutexType1,typename MutexType2,typename MutexType3> | |
void lock(MutexType1& m1,MutexType2& m2,MutexType3& m3) | |
{ | |
unsigned const lock_count=3; | |
unsigned lock_first=0; | |
for(;;) | |
{ | |
switch(lock_first) | |
{ | |
case 0: | |
lock_first=detail::lock_helper(m1,m2,m3); | |
if(!lock_first) | |
return; | |
break; | |
case 1: | |
lock_first=detail::lock_helper(m2,m3,m1); | |
if(!lock_first) | |
return; | |
lock_first=(lock_first+1)%lock_count; | |
break; | |
case 2: | |
lock_first=detail::lock_helper(m3,m1,m2); | |
if(!lock_first) | |
return; | |
lock_first=(lock_first+2)%lock_count; | |
break; | |
} | |
} | |
} | |
template<typename MutexType1,typename MutexType2,typename MutexType3, | |
typename MutexType4> | |
void lock(MutexType1& m1,MutexType2& m2,MutexType3& m3, | |
MutexType4& m4) | |
{ | |
unsigned const lock_count=4; | |
unsigned lock_first=0; | |
for(;;) | |
{ | |
switch(lock_first) | |
{ | |
case 0: | |
lock_first=detail::lock_helper(m1,m2,m3,m4); | |
if(!lock_first) | |
return; | |
break; | |
case 1: | |
lock_first=detail::lock_helper(m2,m3,m4,m1); | |
if(!lock_first) | |
return; | |
lock_first=(lock_first+1)%lock_count; | |
break; | |
case 2: | |
lock_first=detail::lock_helper(m3,m4,m1,m2); | |
if(!lock_first) | |
return; | |
lock_first=(lock_first+2)%lock_count; | |
break; | |
case 3: | |
lock_first=detail::lock_helper(m4,m1,m2,m3); | |
if(!lock_first) | |
return; | |
lock_first=(lock_first+3)%lock_count; | |
break; | |
} | |
} | |
} | |
template<typename MutexType1,typename MutexType2,typename MutexType3, | |
typename MutexType4,typename MutexType5> | |
void lock(MutexType1& m1,MutexType2& m2,MutexType3& m3, | |
MutexType4& m4,MutexType5& m5) | |
{ | |
unsigned const lock_count=5; | |
unsigned lock_first=0; | |
for(;;) | |
{ | |
switch(lock_first) | |
{ | |
case 0: | |
lock_first=detail::lock_helper(m1,m2,m3,m4,m5); | |
if(!lock_first) | |
return; | |
break; | |
case 1: | |
lock_first=detail::lock_helper(m2,m3,m4,m5,m1); | |
if(!lock_first) | |
return; | |
lock_first=(lock_first+1)%lock_count; | |
break; | |
case 2: | |
lock_first=detail::lock_helper(m3,m4,m5,m1,m2); | |
if(!lock_first) | |
return; | |
lock_first=(lock_first+2)%lock_count; | |
break; | |
case 3: | |
lock_first=detail::lock_helper(m4,m5,m1,m2,m3); | |
if(!lock_first) | |
return; | |
lock_first=(lock_first+3)%lock_count; | |
break; | |
case 4: | |
lock_first=detail::lock_helper(m5,m1,m2,m3,m4); | |
if(!lock_first) | |
return; | |
lock_first=(lock_first+4)%lock_count; | |
break; | |
} | |
} | |
} | |
namespace detail | |
{ | |
template<typename Mutex,bool x=is_mutex_type<Mutex>::value> | |
struct try_lock_impl_return | |
{ | |
typedef int type; | |
}; | |
template<typename Iterator> | |
struct try_lock_impl_return<Iterator,false> | |
{ | |
typedef Iterator type; | |
}; | |
template<typename MutexType1,typename MutexType2> | |
int try_lock_impl(MutexType1& m1,MutexType2& m2,is_mutex_type_wrapper<true>) | |
{ | |
return ((int)detail::try_lock_internal(m1,m2))-1; | |
} | |
template<typename Iterator> | |
Iterator try_lock_impl(Iterator begin,Iterator end,is_mutex_type_wrapper<false>); | |
} | |
template<typename MutexType1,typename MutexType2> | |
typename detail::try_lock_impl_return<MutexType1>::type try_lock(MutexType1& m1,MutexType2& m2) | |
{ | |
return detail::try_lock_impl(m1,m2,detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>()); | |
} | |
template<typename MutexType1,typename MutexType2> | |
typename detail::try_lock_impl_return<MutexType1>::type try_lock(const MutexType1& m1,MutexType2& m2) | |
{ | |
return detail::try_lock_impl(m1,m2,detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>()); | |
} | |
template<typename MutexType1,typename MutexType2> | |
typename detail::try_lock_impl_return<MutexType1>::type try_lock(MutexType1& m1,const MutexType2& m2) | |
{ | |
return detail::try_lock_impl(m1,m2,detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>()); | |
} | |
template<typename MutexType1,typename MutexType2> | |
typename detail::try_lock_impl_return<MutexType1>::type try_lock(const MutexType1& m1,const MutexType2& m2) | |
{ | |
return detail::try_lock_impl(m1,m2,detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>()); | |
} | |
template<typename MutexType1,typename MutexType2,typename MutexType3> | |
int try_lock(MutexType1& m1,MutexType2& m2,MutexType3& m3) | |
{ | |
return ((int)detail::try_lock_internal(m1,m2,m3))-1; | |
} | |
template<typename MutexType1,typename MutexType2,typename MutexType3,typename MutexType4> | |
int try_lock(MutexType1& m1,MutexType2& m2,MutexType3& m3,MutexType4& m4) | |
{ | |
return ((int)detail::try_lock_internal(m1,m2,m3,m4))-1; | |
} | |
template<typename MutexType1,typename MutexType2,typename MutexType3,typename MutexType4,typename MutexType5> | |
int try_lock(MutexType1& m1,MutexType2& m2,MutexType3& m3,MutexType4& m4,MutexType5& m5) | |
{ | |
return ((int)detail::try_lock_internal(m1,m2,m3,m4,m5))-1; | |
} | |
namespace detail | |
{ | |
template<typename Iterator> | |
struct range_lock_guard | |
{ | |
Iterator begin; | |
Iterator end; | |
range_lock_guard(Iterator begin_,Iterator end_): | |
begin(begin_),end(end_) | |
{ | |
lock(begin,end); | |
} | |
void release() | |
{ | |
begin=end; | |
} | |
~range_lock_guard() | |
{ | |
for(;begin!=end;++begin) | |
{ | |
begin->unlock(); | |
} | |
} | |
}; | |
template<typename Iterator> | |
Iterator try_lock_impl(Iterator begin,Iterator end,is_mutex_type_wrapper<false>) | |
{ | |
if(begin==end) | |
{ | |
return end; | |
} | |
typedef typename std::iterator_traits<Iterator>::value_type lock_type; | |
unique_lock<lock_type> guard(*begin,try_to_lock); | |
if(!guard.owns_lock()) | |
{ | |
return begin; | |
} | |
Iterator const failed=try_lock(++begin,end); | |
if(failed==end) | |
{ | |
guard.release(); | |
} | |
return failed; | |
} | |
} | |
namespace detail | |
{ | |
template<typename Iterator> | |
void lock_impl(Iterator begin,Iterator end,is_mutex_type_wrapper<false>) | |
{ | |
typedef typename std::iterator_traits<Iterator>::value_type lock_type; | |
if(begin==end) | |
{ | |
return; | |
} | |
bool start_with_begin=true; | |
Iterator second=begin; | |
++second; | |
Iterator next=second; | |
for(;;) | |
{ | |
unique_lock<lock_type> begin_lock(*begin,defer_lock); | |
if(start_with_begin) | |
{ | |
begin_lock.lock(); | |
Iterator const failed_lock=try_lock(next,end); | |
if(failed_lock==end) | |
{ | |
begin_lock.release(); | |
return; | |
} | |
start_with_begin=false; | |
next=failed_lock; | |
} | |
else | |
{ | |
detail::range_lock_guard<Iterator> guard(next,end); | |
if(begin_lock.try_lock()) | |
{ | |
Iterator const failed_lock=try_lock(second,next); | |
if(failed_lock==next) | |
{ | |
begin_lock.release(); | |
guard.release(); | |
return; | |
} | |
start_with_begin=false; | |
next=failed_lock; | |
} | |
else | |
{ | |
start_with_begin=true; | |
next=second; | |
} | |
} | |
} | |
} | |
} | |
} | |
#include <boost/config/abi_suffix.hpp> | |
#endif |