469 lines
13 KiB
C++
469 lines
13 KiB
C++
// 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
|
|
// (C) Copyright 2011-2012 Vicente J. Botet Escriba
|
|
|
|
#ifndef BOOST_THREAD_LOCK_ALGORITHMS_HPP
|
|
#define BOOST_THREAD_LOCK_ALGORITHMS_HPP
|
|
|
|
#include <boost/thread/detail/config.hpp>
|
|
#include <boost/thread/lock_types.hpp>
|
|
#include <boost/thread/lockable_traits.hpp>
|
|
|
|
#include <algorithm>
|
|
#include <iterator>
|
|
|
|
#include <boost/config/abi_prefix.hpp>
|
|
|
|
namespace boost
|
|
{
|
|
namespace detail
|
|
{
|
|
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_)
|
|
{
|
|
boost::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 = boost::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 = boost::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 = boost::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
|