2
0
mirror of https://github.com/boostorg/thread.git synced 2026-01-23 18:12:12 +00:00
Files
thread/src/read_write_mutex.cpp
Michael Glassford 9ad04bb65e Handle locks that timeout.
[SVN r23999]
2004-07-23 18:39:50 +00:00

1176 lines
33 KiB
C++

// Copyright (C) 2002-2003
// David Moore, William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/detail/config.hpp>
#include <boost/assert.hpp>
#include <boost/thread/read_write_mutex.hpp>
#include <boost/thread/xtime.hpp>
#ifdef BOOST_HAS_WINTHREADS
#include <windows.h>
#include <tchar.h>
#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))
inline bool IsDebuggerPresent(void)
{
return false;
}
#endif
#endif
#if defined(BOOST_ASSERT)
# define BOOST_ASSERT_ELSE(expr) if ((BOOST_ASSERT(expr)), false) {} else
#else
# define BOOST_ASSERT_ELSE(expr) if (false) {} else
#endif
bool boost_error(char const* expr, char const* func, char const* file, long line)
{
#if WINVER
using namespace std;
#ifndef ELEMENTS
#define ELEMENTS(a) (sizeof(a)/sizeof(*(a)))
#endif
TCHAR message[200];
_sntprintf(message,ELEMENTS(message),TEXT("Assertion failed (func=%s, file=%s, line=%d): %s"), func, file, line, expr);
::OutputDebugString(message);
if(::IsDebuggerPresent())
::DebugBreak();
#endif
return false;
}
namespace boost {
namespace detail {
namespace thread {
inline bool valid_lock(int state)
{
return (state >= 0) || (state == -1);
}
inline bool valid_read_write_lock(int state)
{
return state != 0;
}
inline bool valid_read_lock(int state)
{
return state > 0;
}
inline bool valid_read_lockable(int state)
{
return state >= 0;
}
inline bool valid_write_lock(int state)
{
return state == -1;
}
inline bool valid_write_lockable(int state)
{
return state == 0;
}
template<typename Mutex>
void read_write_mutex_impl<Mutex>::do_read_lock()
{
typename Mutex::scoped_lock l(m_prot);
BOOST_ASSERT(valid_lock(m_state));
if (m_sp == read_write_scheduling_policy::reader_priority)
{
//Reader priority: wait while write-locked
int loop_count = 0;
while (m_state == -1)
{
BOOST_ASSERT(++loop_count == 1); //Check for invalid loop conditions (but will also detect spurious wakeups)
++m_num_waiting_readers;
m_waiting_readers.wait(l);
--m_num_waiting_readers;
}
}
else if (m_sp == read_write_scheduling_policy::writer_priority)
{
//Writer priority: wait while write-locked or while writers are waiting
int loop_count = 0;
while (m_state == -1 || m_num_waiting_writers > 0)
{
BOOST_ASSERT(++loop_count == 1); //Check for invalid loop conditions (but will also detect spurious wakeups)
++m_num_waiting_readers;
m_waiting_readers.wait(l);
--m_num_waiting_readers;
}
}
else BOOST_ASSERT_ELSE(m_sp == read_write_scheduling_policy::alternating_single_read || m_sp == read_write_scheduling_policy::alternating_many_reads)
{
//Alternating priority: wait while write-locked or while not readers' turn
int loop_count = 0;
while (m_state == -1 || m_num_readers_to_wake == 0)
{
BOOST_ASSERT(++loop_count == 1); //Check for invalid loop conditions (but will also detect spurious wakeups)
++m_num_waiting_readers;
m_waiting_readers.wait(l);
--m_num_waiting_readers;
}
BOOST_ASSERT(m_num_readers_to_wake > 0);
--m_num_readers_to_wake;
}
//Obtain a read lock
BOOST_ASSERT(valid_read_lockable(m_state));
++m_state;
/*
Set m_readers_next in the lock function rather than the
unlock function to prevent thread starvation that can happen,
e.g., like this: if all writer threads demote themselves
to reader threads before unlocking, they will unlock using
do_read_unlock() which will set m_readers_next = false;
if there are enough writer threads, this will prevent any
"true" reader threads from ever obtaining the lock.
*/
m_readers_next = false;
BOOST_ASSERT(valid_read_lock(m_state));
}
template<typename Mutex>
void read_write_mutex_impl<Mutex>::do_write_lock()
{
typename Mutex::scoped_lock l(m_prot);
BOOST_ASSERT(valid_lock(m_state));
if (m_sp == read_write_scheduling_policy::reader_priority)
{
//Reader priority: wait while locked or while readers are waiting
int loop_count = 0;
while (m_state != 0 || m_num_waiting_readers > 0)
{
BOOST_ASSERT(++loop_count == 1); //Check for invalid loop conditions (but will also detect spurious wakeups)
++m_num_waiting_writers;
m_waiting_writers.wait(l);
--m_num_waiting_writers;
}
}
else if (m_sp == read_write_scheduling_policy::writer_priority)
{
//Shut down extra readers that were scheduled only because of no waiting writers
m_num_readers_to_wake = 0;
//Writer priority: wait while locked
int loop_count = 0;
while (m_state != 0)
{
BOOST_ASSERT(++loop_count == 1); //Check for invalid loop conditions (but will also detect spurious wakeups)
++m_num_waiting_writers;
m_waiting_writers.wait(l);
--m_num_waiting_writers;
}
}
else BOOST_ASSERT_ELSE(m_sp == read_write_scheduling_policy::alternating_single_read || m_sp == read_write_scheduling_policy::alternating_many_reads)
{
//Shut down extra readers that were scheduled only because of no waiting writers
if (m_sp == read_write_scheduling_policy::alternating_single_read && m_num_waiting_writers == 0)
m_num_readers_to_wake = (m_readers_next && m_num_readers_to_wake > 0) ? 1 : 0;
//Alternating priority: wait while locked or while not writers' turn
int loop_count = 0;
while (m_state != 0 || m_num_readers_to_wake > 0)
{
BOOST_ASSERT(++loop_count == 1); //Check for invalid loop conditions (but will also detect spurious wakeups)
++m_num_waiting_writers;
m_waiting_writers.wait(l);
--m_num_waiting_writers;
}
}
//Obtain a write lock
BOOST_ASSERT(valid_write_lockable(m_state));
m_state = -1;
//See note in read_write_mutex_impl<>::do_read_lock() as to why
//m_readers_next should be set here
m_readers_next = true;
BOOST_ASSERT(valid_write_lock(m_state));
}
template<typename Mutex>
bool read_write_mutex_impl<Mutex>::do_try_read_lock()
{
typename Mutex::scoped_try_lock l(m_prot);
BOOST_ASSERT(valid_lock(m_state));
if (!l.locked())
return false;
bool fail;
if (m_sp == read_write_scheduling_policy::reader_priority)
{
//Reader priority: fail if write-locked
fail = (m_state == -1);
}
else if (m_sp == read_write_scheduling_policy::writer_priority)
{
//Writer priority: fail if write-locked or if writers are waiting
fail = (m_state == -1 || m_num_waiting_writers > 0);
}
else BOOST_ASSERT_ELSE(m_sp == read_write_scheduling_policy::alternating_single_read || m_sp == read_write_scheduling_policy::alternating_many_reads)
{
//Alternating priority: fail if write-locked or if not readers' turn
fail = (m_state == -1 || m_num_readers_to_wake == 0);
if (!fail)
{
BOOST_ASSERT(m_num_readers_to_wake > 0);
--m_num_readers_to_wake;
}
}
if (!fail)
{
//Obtain a read lock
BOOST_ASSERT(valid_read_lockable(m_state));
++m_state;
//See note in read_write_mutex_impl<>::do_read_lock() as to why
//m_readers_next should be set here
m_readers_next = false;
BOOST_ASSERT(valid_read_lock(m_state));
//Should be read-locked
}
else
{
BOOST_ASSERT(valid_write_lock(m_state) || m_num_waiting_writers > 0);
//Should be write-locked or
//writer should be waiting
}
return !fail;
}
template<typename Mutex>
bool read_write_mutex_impl<Mutex>::do_try_write_lock()
{
typename Mutex::scoped_try_lock l(m_prot);
BOOST_ASSERT(valid_lock(m_state));
if (!l.locked())
return false;
bool fail;
if (m_sp == read_write_scheduling_policy::reader_priority)
{
//Reader priority: fail if locked or if readers are waiting
fail = (m_state != 0 || m_num_waiting_readers > 0);
}
else if (m_sp == read_write_scheduling_policy::writer_priority)
{
//Writer priority: fail if locked
fail = (m_state != 0);
}
else BOOST_ASSERT_ELSE(m_sp == read_write_scheduling_policy::alternating_single_read || m_sp == read_write_scheduling_policy::alternating_many_reads)
{
//Alternating priority: fail if locked or if not writers' turn
fail = (m_state != 0 || m_num_readers_to_wake > 0);
}
if (!fail)
{
//Obtain a write lock
BOOST_ASSERT(valid_write_lockable(m_state));
m_state = -1;
//See note in read_write_mutex_impl<>::do_read_lock() as to why
//m_readers_next should be set here
m_readers_next = true;
BOOST_ASSERT(valid_write_lock(m_state));
//Should be write-locked
}
else
{
BOOST_ASSERT(valid_read_write_lock(m_state) || m_num_readers_to_wake > 0);
//Should be read-locked or write-locked, or
//reader should be waking
}
return !fail;
}
template<typename Mutex>
bool read_write_mutex_impl<Mutex>::do_timed_read_lock(const boost::xtime &xt)
{
typename Mutex::scoped_timed_lock l(m_prot, xt);
BOOST_ASSERT(valid_lock(m_state));
if (!l.locked())
return false;
bool fail;
if (m_sp == read_write_scheduling_policy::reader_priority)
{
//Reader priority: wait while write-locked
int loop_count = 0;
while (m_state == -1)
{
BOOST_ASSERT(++loop_count == 1); //Check for invalid loop conditions (but will also detect spurious wakeups)
++m_num_waiting_readers;
if (!m_waiting_readers.timed_wait(l, xt))
{
--m_num_waiting_readers;
fail = true;
break;
}
--m_num_waiting_readers;
}
}
else if (m_sp == read_write_scheduling_policy::writer_priority)
{
//Writer priority: wait while write-locked or while writers are waiting
int loop_count = 0;
while (m_state == -1 || m_num_waiting_writers > 0)
{
BOOST_ASSERT(++loop_count == 1); //Check for invalid loop conditions (but will also detect spurious wakeups)
++m_num_waiting_readers;
if (!m_waiting_readers.timed_wait(l, xt))
{
--m_num_waiting_readers;
fail = true;
break;
}
--m_num_waiting_readers;
}
}
else BOOST_ASSERT_ELSE(m_sp == read_write_scheduling_policy::alternating_single_read || m_sp == read_write_scheduling_policy::alternating_many_reads)
{
//Alternating priority: wait while write-locked or while not readers' turn
int loop_count = 0;
while (m_state == -1 || m_num_readers_to_wake == 0)
{
BOOST_ASSERT(++loop_count == 1); //Check for invalid loop conditions (but will also detect spurious wakeups)
++m_num_waiting_readers;
if (!m_waiting_readers.timed_wait(l, xt))
{
--m_num_waiting_readers;
fail = true;
break;
}
--m_num_waiting_readers;
}
if (!fail)
{
BOOST_ASSERT(m_num_readers_to_wake > 0);
--m_num_readers_to_wake;
}
}
if (!fail)
{
//Obtain a read lock
BOOST_ASSERT(valid_read_lockable(m_state));
++m_state;
//See note in read_write_mutex_impl<>::do_read_lock() as to why
//m_readers_next should be set here
m_readers_next = false;
BOOST_ASSERT(valid_read_lock(m_state));
//Should be read-locked
}
else
{
if (m_num_readers_to_wake > 0)
{
//If there were readers scheduled to wake,
//decrement the number in case we were that reader.
//If only one was scheduled to wake, the scheduling
//algorithm will schedule another if one is available;
//if more than one, one fewer reader will run before
//the scheduling algorithm is called again. This last
//case is not ideal, especially if a lot of waiting
//readers timeout, but without knowing whether
//we were actually one of the readers that was
//scheduled to wake it's difficult to come up
//with a better plan.
--m_num_readers_to_wake;
}
if (m_state == 0)
{
//If there is no thread with a lock that will
//call do_scheduling_impl() when it unlocks, call it ourselves
do_timeout_scheduling_impl();
}
}
return !fail;
}
template<typename Mutex>
bool read_write_mutex_impl<Mutex>::do_timed_write_lock(const boost::xtime &xt)
{
typename Mutex::scoped_timed_lock l(m_prot, xt);
BOOST_ASSERT(valid_lock(m_state));
if (!l.locked())
return false;
bool fail;
if (m_sp == read_write_scheduling_policy::reader_priority)
{
//Reader priority: wait while locked or while readers are waiting
int loop_count = 0;
while (m_state != 0 || m_num_waiting_readers > 0)
{
BOOST_ASSERT(++loop_count == 1); //Check for invalid loop conditions (but will also detect spurious wakeups)
++m_num_waiting_writers;
if (!m_waiting_writers.timed_wait(l, xt))
{
--m_num_waiting_writers;
fail = true;
break;
}
--m_num_waiting_writers;
}
}
else if (m_sp == read_write_scheduling_policy::writer_priority)
{
//Shut down extra readers that were scheduled only because of no waiting writers
m_num_readers_to_wake = 0;
//Writer priority: wait while locked
int loop_count = 0;
while (m_state != 0)
{
BOOST_ASSERT(++loop_count == 1); //Check for invalid loop conditions (but will also detect spurious wakeups)
++m_num_waiting_writers;
if (!m_waiting_writers.timed_wait(l, xt))
{
--m_num_waiting_writers;
fail = true;
break;
}
--m_num_waiting_writers;
}
}
else BOOST_ASSERT_ELSE(m_sp == read_write_scheduling_policy::alternating_single_read || m_sp == read_write_scheduling_policy::alternating_many_reads)
{
//Shut down extra readers that were scheduled only because of no waiting writers
if (m_sp == read_write_scheduling_policy::alternating_single_read && m_num_waiting_writers == 0)
m_num_readers_to_wake = (m_readers_next && m_num_readers_to_wake > 0) ? 1 : 0;
//Alternating priority: wait while locked or while not writers' turn
int loop_count = 0;
while (m_state != 0 || m_num_readers_to_wake > 0)
{
BOOST_ASSERT(++loop_count == 1); //Check for invalid loop conditions (but will also detect spurious wakeups)
++m_num_waiting_writers;
if (!m_waiting_writers.timed_wait(l, xt))
{
--m_num_waiting_writers;
fail = true;
break;
}
--m_num_waiting_writers;
}
}
if (!fail)
{
//Obtain a write lock
BOOST_ASSERT(valid_write_lockable(m_state));
m_state = -1;
//See note in read_write_mutex_impl<>::do_read_lock() as to why
//m_readers_next should be set here
m_readers_next = true;
BOOST_ASSERT(valid_write_lock(m_state));
//Should be write-locked
}
else
{
if (m_state == 0)
{
//If there is no thread with a lock that will
//call do_scheduling_impl() when it unlocks, call it ourselves
do_timeout_scheduling_impl();
}
}
return !fail;
}
template<typename Mutex>
void read_write_mutex_impl<Mutex>::do_read_unlock()
{
typename Mutex::scoped_lock l(m_prot);
BOOST_ASSERT(valid_read_lock(m_state));
if (m_state > 0)
--m_state;
else //not read-locked
throw lock_error();
if (m_state == 0)
do_unlock_scheduling_impl();
BOOST_ASSERT(valid_lock(m_state));
}
template<typename Mutex>
void read_write_mutex_impl<Mutex>::do_write_unlock()
{
typename Mutex::scoped_lock l(m_prot);
BOOST_ASSERT(valid_write_lock(m_state));
if (m_state == -1)
m_state = 0;
else BOOST_ASSERT_ELSE(m_state >= 0)
throw lock_error(); // Trying to release a reader-locked or unlocked mutex???
do_unlock_scheduling_impl();
BOOST_ASSERT(valid_lock(m_state));
}
template<typename Mutex>
bool read_write_mutex_impl<Mutex>::do_demote_to_read_lock_impl()
{
BOOST_ASSERT(valid_write_lock(m_state));
if (m_state == -1)
{
//Convert from write lock to read lock
m_state = 1;
//If the conditions are right, release other readers
do_demote_scheduling_impl();
//Lock demoted
BOOST_ASSERT(valid_read_lock(m_state));
return true;
}
else BOOST_ASSERT_ELSE(m_state >= 0)
{
//Lock is read-locked or unlocked can't be demoted
throw lock_error();
return false;
}
}
template<typename Mutex>
void read_write_mutex_impl<Mutex>::do_demote_to_read_lock()
{
typename Mutex::scoped_lock l(m_prot);
BOOST_ASSERT(valid_write_lock(m_state));
do_demote_to_read_lock_impl();
}
template<typename Mutex>
bool read_write_mutex_impl<Mutex>::do_try_demote_to_read_lock()
{
typename Mutex::scoped_try_lock l(m_prot);
BOOST_ASSERT(valid_write_lock(m_state));
if (!l.locked())
return false;
else //(l.locked())
return do_demote_to_read_lock_impl();
}
template<typename Mutex>
bool read_write_mutex_impl<Mutex>::do_timed_demote_to_read_lock(const boost::xtime &xt)
{
typename Mutex::scoped_timed_lock l(m_prot, xt);
BOOST_ASSERT(valid_write_lock(m_state));
if (!l.locked())
return false;
else //(l.locked())
return do_demote_to_read_lock_impl();
}
template<typename Mutex>
void read_write_mutex_impl<Mutex>::do_promote_to_write_lock()
{
typename Mutex::scoped_lock l(m_prot);
BOOST_ASSERT(valid_read_lock(m_state));
if (m_state == 1)
{
//Convert from read lock to write lock
m_state = -1;
//Lock promoted
BOOST_ASSERT(valid_write_lock(m_state));
}
else if (m_state <= 0)
{
//Lock is write-locked or unlocked can't be promoted
throw lock_error();
}
else if (m_state_waiting_promotion)
{
//Someone else is already trying to promote. Avoid deadlock by throwing exception.
throw lock_error();
}
else BOOST_ASSERT_ELSE(m_state > 1 && !m_state_waiting_promotion)
{
++m_num_waiting_writers;
m_state_waiting_promotion = true;
int loop_count = 0;
while (m_state > 1)
{
BOOST_ASSERT(++loop_count == 1); //Check for invalid loop conditions (but will also detect spurious wakeups)
m_waiting_promotion.wait(l);
}
m_state_waiting_promotion = false;
--m_num_waiting_writers;
BOOST_ASSERT(m_num_waiting_writers >= 0);
BOOST_ASSERT(m_state == 1);
//Convert from read lock to write lock
m_state = -1;
//Lock promoted
BOOST_ASSERT(valid_write_lock(m_state));
}
}
template<typename Mutex>
bool read_write_mutex_impl<Mutex>::do_try_promote_to_write_lock()
{
typename Mutex::scoped_try_lock l(m_prot);
BOOST_ASSERT(valid_read_lock(m_state));
if (!l.locked())
return false;
else
{
if (m_state == 1)
{
//Convert from read lock to write lock
m_state = -1;
//Lock promoted
BOOST_ASSERT(valid_write_lock(m_state));
return true;
}
else if (m_state <= 0)
{
//Lock is write-locked or unlocked can't be promoted
throw lock_error();
}
else if (m_state_waiting_promotion)
{
//Someone else is already trying to promote. Avoid deadlock by returning false.
return false;
}
else BOOST_ASSERT_ELSE(m_state > 1 && !m_state_waiting_promotion)
{
//There are other readers, so we can't promote
return false;
}
}
}
template<typename Mutex>
bool read_write_mutex_impl<Mutex>::do_timed_promote_to_write_lock(const boost::xtime &xt)
{
typename Mutex::scoped_timed_lock l(m_prot, xt);
BOOST_ASSERT(valid_read_lock(m_state));
if (!l.locked())
return false;
else
{
if (m_state == 1)
{
//Convert from read lock to write lock
m_state = -1;
//Lock promoted
BOOST_ASSERT(valid_write_lock(m_state));
return true;
}
else if (m_state <= 0)
{
//Lock is not read-locked and can't be promoted
throw lock_error();
}
else if (m_state_waiting_promotion)
{
//Someone else is already trying to promote. Avoid deadlock by returning false.
return false;
}
else BOOST_ASSERT_ELSE(m_state > 1 && !m_state_waiting_promotion)
{
++m_num_waiting_writers;
m_state_waiting_promotion = true;
int loop_count = 0;
while (m_state > 1)
{
BOOST_ASSERT(++loop_count == 1); //Check for invalid loop conditions (but will also detect spurious wakeups)
if (!m_waiting_promotion.timed_wait(l, xt))
{
m_state_waiting_promotion = false;
--m_num_waiting_writers;
return false;
}
}
m_state_waiting_promotion = false;
--m_num_waiting_writers;
BOOST_ASSERT(m_num_waiting_writers >= 0);
BOOST_ASSERT(m_state == 1);
//Convert from read lock to write lock
m_state = -1;
//Lock promoted
BOOST_ASSERT(valid_write_lock(m_state));
return true;
}
}
}
template<typename Mutex>
bool read_write_mutex_impl<Mutex>::locked()
{
int state = m_state;
BOOST_ASSERT(valid_lock(state));
return state != 0;
}
template<typename Mutex>
read_write_lock_state::read_write_lock_state_enum read_write_mutex_impl<Mutex>::state()
{
int state = m_state;
BOOST_ASSERT(valid_lock(state));
if (state > 0)
{
BOOST_ASSERT(valid_read_lock(state));
return read_write_lock_state::read_locked;
}
else if (state == -1)
{
BOOST_ASSERT(valid_write_lock(state));
return read_write_lock_state::write_locked;
}
else BOOST_ASSERT_ELSE(state == 0)
return read_write_lock_state::unlocked;
}
template<typename Mutex>
void read_write_mutex_impl<Mutex>::do_unlock_scheduling_impl()
{
BOOST_ASSERT(m_state == 0);
do_scheduling_impl();
}
template<typename Mutex>
void read_write_mutex_impl<Mutex>::do_timeout_scheduling_impl()
{
BOOST_ASSERT(m_state == 0);
do_scheduling_impl();
}
template<typename Mutex>
void read_write_mutex_impl<Mutex>::do_demote_scheduling_impl()
{
BOOST_ASSERT(m_state == 1);
do_scheduling_impl();
}
template<typename Mutex>
void read_write_mutex_impl<Mutex>::do_scheduling_impl()
{
bool demotion = m_state > 0; //Releasing readers after lock demotion?
BOOST_ASSERT(valid_read_lockable(m_state));
if (m_num_waiting_writers > 0 && m_num_waiting_readers > 0)
{
//Both readers and writers waiting: use scheduling policy
if (m_sp == read_write_scheduling_policy::reader_priority)
{
m_num_readers_to_wake = m_num_waiting_readers;
m_waiting_readers.notify_all();
}
else if (m_sp == read_write_scheduling_policy::writer_priority)
{
if (!demotion)
{
if (m_state_waiting_promotion)
m_waiting_promotion.notify_one();
else
m_waiting_writers.notify_one();
}
}
else if (m_sp == read_write_scheduling_policy::alternating_single_read)
{
if (m_num_readers_to_wake > 0)
{
//Let the already woken threads work
}
else if (m_readers_next)
{
m_num_readers_to_wake = 1;
m_waiting_readers.notify_one();
}
else
{
if (!demotion)
{
if (m_state_waiting_promotion)
m_waiting_promotion.notify_one();
else
m_waiting_writers.notify_one();
}
}
}
else BOOST_ASSERT_ELSE(m_sp == read_write_scheduling_policy::alternating_many_reads)
{
if (m_num_readers_to_wake > 0)
{
//Let the already woken threads work
}
else if (m_readers_next)
{
m_num_readers_to_wake = m_num_waiting_readers;
m_waiting_readers.notify_all();
}
else
{
if (!demotion)
{
if (m_state_waiting_promotion)
m_waiting_promotion.notify_one();
else
m_waiting_writers.notify_one();
}
}
}
}
else if (m_num_waiting_writers > 0)
{
if (!demotion)
{
//Only writers waiting--scheduling policy doesn't matter
if (m_state_waiting_promotion)
m_waiting_promotion.notify_one();
else
m_waiting_writers.notify_one();
}
}
else if (m_num_waiting_readers > 0)
{
//Only readers waiting--scheduling policy doesn't matter
m_num_readers_to_wake = m_num_waiting_readers;
m_waiting_readers.notify_all();
}
}
} // namespace thread
} // namespace detail
void read_write_mutex::do_read_lock()
{
m_impl.do_read_lock();
}
void read_write_mutex::do_write_lock()
{
m_impl.do_write_lock();
}
void read_write_mutex::do_read_unlock()
{
m_impl.do_read_unlock();
}
void read_write_mutex::do_write_unlock()
{
m_impl.do_write_unlock();
}
void read_write_mutex::do_demote_to_read_lock()
{
m_impl.do_demote_to_read_lock();
}
void read_write_mutex::do_promote_to_write_lock()
{
m_impl.do_promote_to_write_lock();
}
bool read_write_mutex::locked()
{
return m_impl.locked();
}
read_write_lock_state::read_write_lock_state_enum read_write_mutex::state()
{
return m_impl.state();
}
void try_read_write_mutex::do_read_lock()
{
m_impl.do_read_lock();
}
void try_read_write_mutex::do_write_lock()
{
m_impl.do_write_lock();
}
void try_read_write_mutex::do_write_unlock()
{
m_impl.do_write_unlock();
}
void try_read_write_mutex::do_read_unlock()
{
m_impl.do_read_unlock();
}
bool try_read_write_mutex::do_try_read_lock()
{
return m_impl.do_try_read_lock();
}
bool try_read_write_mutex::do_try_write_lock()
{
return m_impl.do_try_write_lock();
}
void try_read_write_mutex::do_demote_to_read_lock()
{
m_impl.do_demote_to_read_lock();
}
bool try_read_write_mutex::do_try_demote_to_read_lock()
{
return m_impl.do_try_demote_to_read_lock();
}
void try_read_write_mutex::do_promote_to_write_lock()
{
m_impl.do_promote_to_write_lock();
}
bool try_read_write_mutex::do_try_promote_to_write_lock()
{
return m_impl.do_try_promote_to_write_lock();
}
bool try_read_write_mutex::locked()
{
return m_impl.locked();
}
read_write_lock_state::read_write_lock_state_enum try_read_write_mutex::state()
{
return m_impl.state();
}
void timed_read_write_mutex::do_read_lock()
{
m_impl.do_read_lock();
}
void timed_read_write_mutex::do_write_lock()
{
m_impl.do_write_lock();
}
void timed_read_write_mutex::do_read_unlock()
{
m_impl.do_read_unlock();
}
void timed_read_write_mutex::do_write_unlock()
{
m_impl.do_write_unlock();
}
bool timed_read_write_mutex::do_try_read_lock()
{
return m_impl.do_try_read_lock();
}
bool timed_read_write_mutex::do_try_write_lock()
{
return m_impl.do_try_write_lock();
}
bool timed_read_write_mutex::do_timed_read_lock(const xtime &xt)
{
return m_impl.do_timed_read_lock(xt);
}
bool timed_read_write_mutex::do_timed_write_lock(const xtime &xt)
{
return m_impl.do_timed_write_lock(xt);
}
void timed_read_write_mutex::do_demote_to_read_lock()
{
m_impl.do_demote_to_read_lock();
}
bool timed_read_write_mutex::do_try_demote_to_read_lock()
{
return m_impl.do_try_demote_to_read_lock();
}
bool timed_read_write_mutex::do_timed_demote_to_read_lock(const xtime &xt)
{
return m_impl.do_timed_demote_to_read_lock(xt);
}
void timed_read_write_mutex::do_promote_to_write_lock()
{
m_impl.do_promote_to_write_lock();
}
bool timed_read_write_mutex::do_try_promote_to_write_lock()
{
return m_impl.do_try_promote_to_write_lock();
}
bool timed_read_write_mutex::do_timed_promote_to_write_lock(const xtime &xt)
{
return m_impl.do_timed_promote_to_write_lock(xt);
}
bool timed_read_write_mutex::locked()
{
return m_impl.locked();
}
read_write_lock_state::read_write_lock_state_enum timed_read_write_mutex::state()
{
return m_impl.state();
}
//Explicit instantiations of read/write locks to catch syntax errors in templates
template class boost::detail::thread::scoped_read_write_lock<read_write_mutex>;
template class boost::detail::thread::scoped_read_write_lock<try_read_write_mutex>;
template class boost::detail::thread::scoped_read_write_lock<timed_read_write_mutex>;
//template class boost::detail::thread::scoped_try_read_write_lock<read_write_mutex>;
template class boost::detail::thread::scoped_try_read_write_lock<try_read_write_mutex>;
template class boost::detail::thread::scoped_try_read_write_lock<timed_read_write_mutex>;
//template class boost::detail::thread::scoped_timed_read_write_lock<read_write_mutex>;
//template class boost::detail::thread::scoped_timed_read_write_lock<try_read_write_mutex>;
template class boost::detail::thread::scoped_timed_read_write_lock<timed_read_write_mutex>;
//Explicit instantiations of read locks to catch syntax errors in templates
template class boost::detail::thread::scoped_read_lock<read_write_mutex>;
template class boost::detail::thread::scoped_read_lock<try_read_write_mutex>;
template class boost::detail::thread::scoped_read_lock<timed_read_write_mutex>;
//template class boost::detail::thread::scoped_try_read_lock<read_write_mutex>;
template class boost::detail::thread::scoped_try_read_lock<try_read_write_mutex>;
template class boost::detail::thread::scoped_try_read_lock<timed_read_write_mutex>;
//template class boost::detail::thread::scoped_timed_read_lock<read_write_mutex>;
//template class boost::detail::thread::scoped_timed_read_lock<try_read_write_mutex>;
template class boost::detail::thread::scoped_timed_read_lock<timed_read_write_mutex>;
//Explicit instantiations of write locks to catch syntax errors in templates
template class boost::detail::thread::scoped_write_lock<read_write_mutex>;
template class boost::detail::thread::scoped_write_lock<try_read_write_mutex>;
template class boost::detail::thread::scoped_write_lock<timed_read_write_mutex>;
//template class boost::detail::thread::scoped_try_write_lock<read_write_mutex>;
template class boost::detail::thread::scoped_try_write_lock<try_read_write_mutex>;
template class boost::detail::thread::scoped_try_write_lock<timed_read_write_mutex>;
//template class boost::detail::thread::scoped_timed_write_lock<read_write_mutex>;
//template class boost::detail::thread::scoped_timed_write_lock<try_read_write_mutex>;
template class boost::detail::thread::scoped_timed_write_lock<timed_read_write_mutex>;
} // namespace boost
// Change Log:
// 10 Mar 02
// Original version.
// 4 May 04 GlassfordM
// For additional changes, see read_write_mutex.hpp.
// Add many assertions to test validity of mutex state and operations.
// Rework scheduling algorithm due to addition of lock promotion and
// demotion.
// Add explicit template instantiations to catch syntax errors
// in templates.