mirror of
https://github.com/boostorg/thread.git
synced 2026-02-03 09:42:16 +00:00
Compare commits
32 Commits
boost-1.32
...
boost-1.33
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
38592947ba | ||
|
|
9ca3c5b13f | ||
|
|
7445f79dd4 | ||
|
|
aa240e61d9 | ||
|
|
2954e932ce | ||
|
|
5be79cc858 | ||
|
|
4a9d97d22d | ||
|
|
f4f3433854 | ||
|
|
26bffa3740 | ||
|
|
69e52a9882 | ||
|
|
cc8de48849 | ||
|
|
9d7c119f94 | ||
|
|
6ba9fd1b60 | ||
|
|
fb6250eb94 | ||
|
|
bc73368c96 | ||
|
|
3068f0c62c | ||
|
|
8e00803c83 | ||
|
|
087b69b629 | ||
|
|
3b237267fb | ||
|
|
b9dbb1ed45 | ||
|
|
41d3b29ec0 | ||
|
|
05ceb8b1e2 | ||
|
|
80d3925b8d | ||
|
|
2cd6cbeacc | ||
|
|
6382846f6c | ||
|
|
349d0fd74b | ||
|
|
9c88855bf4 | ||
|
|
f0e6cdfcb5 | ||
|
|
af9864a1b5 | ||
|
|
8ac145e667 | ||
|
|
39f7afc7d0 | ||
|
|
113b974bb7 |
@@ -46,7 +46,6 @@ import ./threads ;
|
||||
: ## requirements ##
|
||||
<sysinclude>$(BOOST_ROOT) #:should be unnecessary (because already included in thread_base)
|
||||
<define>BOOST_THREAD_BUILD_LIB=1
|
||||
<runtime-link>static
|
||||
# the common names rule ensures that the library will
|
||||
# be named according to the rules used by the install
|
||||
# and auto-link features:
|
||||
@@ -102,7 +101,8 @@ import ./threads ;
|
||||
<template>boost_thread_lib_base
|
||||
: ## requirements ##
|
||||
<define>BOOST_THREAD_LIB_NAME=$(boost_thread_lib_name_ptw32)
|
||||
$(pthreads-win32)
|
||||
$(boost_thread_lib_settings_ptw32)
|
||||
: ## default build ##
|
||||
;
|
||||
|
||||
dll $(boost_thread_lib_name_ptw32)
|
||||
@@ -110,7 +110,8 @@ import ./threads ;
|
||||
<template>boost_thread_dll_base
|
||||
: ## requirements ##
|
||||
<define>BOOST_THREAD_LIB_NAME=$(boost_thread_lib_name_ptw32)
|
||||
$(pthreads-win32)
|
||||
$(boost_thread_lib_settings_ptw32)
|
||||
: ## default build ##
|
||||
;
|
||||
|
||||
stage bin-stage
|
||||
|
||||
@@ -54,7 +54,7 @@ last-revision="$Date$">
|
||||
<title>ACM Computing Surveys</title>
|
||||
<volumenum>Vol. 5</volumenum>
|
||||
<issuenum>No. 4</issuenum>
|
||||
<date>December, 1983</date>
|
||||
<date>December, 1973</date>
|
||||
</biblioset>
|
||||
<biblioset relation="article">
|
||||
<author>0-201-63392-2
|
||||
|
||||
@@ -195,7 +195,7 @@
|
||||
and constructed for the Mutex object.</para>
|
||||
|
||||
<para>A Mutex is
|
||||
<ulink url="../../utility/utility.htm#Class%20noncopyable">
|
||||
<ulink url="../../libs/utility/utility.htm#Class%20noncopyable">
|
||||
NonCopyable</ulink>.</para>
|
||||
<para>For a Mutex type <code>M</code>
|
||||
and an object <code>m</code> of that type,
|
||||
@@ -1180,7 +1180,7 @@
|
||||
the specified time, if any). A
|
||||
read-lock will be granted to all pending readers
|
||||
before any other thread can acquire a write-lock.
|
||||
<p>TODO: try-lock, timed-lock.</p>
|
||||
<para>TODO: try-lock, timed-lock.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
@@ -1188,7 +1188,7 @@
|
||||
<entry>write-lock</entry>
|
||||
<entry>Grant the write-lock immediately, if and
|
||||
only if there are no pending read-lock requests.
|
||||
<p>TODO: try-lock, timed-lock.</p>
|
||||
<para>TODO: try-lock, timed-lock.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
@@ -1200,7 +1200,7 @@
|
||||
for read-locks exist. If other write-lock
|
||||
requests exist, the lock is granted in accordance
|
||||
with the intra-class scheduling policy.
|
||||
<p>TODO: try-lock, timed-lock.</p>
|
||||
<para>TODO: try-lock, timed-lock.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
@@ -1212,18 +1212,18 @@
|
||||
for read-locks exist. If other write-lock
|
||||
requests exist, the lock is granted in accordance
|
||||
with the intra-class scheduling policy.
|
||||
<p>TODO: try-lock, timed-lock.</p>
|
||||
<para>TODO: try-lock, timed-lock.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>read-locked</entry>
|
||||
<entry>promote</entry>
|
||||
<entry><p>TODO</p></entry>
|
||||
<entry><para>TODO</para></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>write-locked</entry>
|
||||
<entry>demote</entry>
|
||||
<entry><p>TODO</p></entry>
|
||||
<entry><para>TODO</para></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
@@ -1261,7 +1261,7 @@
|
||||
<entry>Grant the additional read-lock immediately,
|
||||
<emphasis role="bold">IF</emphasis> no outstanding
|
||||
requests for a write-lock exist; otherwise TODO.
|
||||
<p>TODO: try-lock, timed-lock.</p>
|
||||
<para>TODO: try-lock, timed-lock.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
@@ -1272,7 +1272,7 @@
|
||||
releases its lock. The read lock will be granted
|
||||
once no other outstanding write-lock requests
|
||||
exist.
|
||||
<p>TODO: try-lock, timed-lock.</p>
|
||||
<para>TODO: try-lock, timed-lock.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
@@ -1289,7 +1289,7 @@
|
||||
is granted in accordance with the intra-class
|
||||
scheduling policy. This request will be granted
|
||||
before any new read-lock requests are granted.
|
||||
<p>TODO: try-lock, timed-lock.</p>
|
||||
<para>TODO: try-lock, timed-lock.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
@@ -1301,18 +1301,18 @@
|
||||
granted in accordance with the intra-class
|
||||
scheduling policy. This request will be granted
|
||||
before any new read-lock requests are granted.
|
||||
<p>TODO: try-lock, timed-lock.</p>
|
||||
<para>TODO: try-lock, timed-lock.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>read-locked</entry>
|
||||
<entry>promote</entry>
|
||||
<entry><p>TODO</p></entry>
|
||||
<entry><para>TODO</para></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>write-locked</entry>
|
||||
<entry>demote</entry>
|
||||
<entry><p>TODO</p></entry>
|
||||
<entry><para>TODO</para></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
@@ -1355,7 +1355,7 @@
|
||||
write-locks is granted and released. If other
|
||||
read-lock requests exist, all read-locks will be
|
||||
granted as a group.
|
||||
<p>TODO: try-lock, timed-lock.</p>
|
||||
<para>TODO: try-lock, timed-lock.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
@@ -1366,7 +1366,7 @@
|
||||
outstanding write-lock requests exist, they will
|
||||
have to wait until all current read-lock requests
|
||||
are serviced.
|
||||
<p>TODO: try-lock, timed-lock.</p>
|
||||
<para>TODO: try-lock, timed-lock.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
@@ -1385,7 +1385,7 @@
|
||||
lock will be granted to one of them in accordance
|
||||
with the intra-class scheduling policy.</para>
|
||||
|
||||
<p>TODO: try-lock, timed-lock.</p>
|
||||
<para>TODO: try-lock, timed-lock.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
@@ -1399,18 +1399,18 @@
|
||||
released. If other write-lock requests exist,
|
||||
this lock will be granted in accordance with the
|
||||
intra-class scheduling policy.
|
||||
<p>TODO: try-lock, timed-lock.</p>
|
||||
<para>TODO: try-lock, timed-lock.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>read-locked</entry>
|
||||
<entry>promote</entry>
|
||||
<entry><p>TODO</p></entry>
|
||||
<entry><para>TODO</para></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>write-locked</entry>
|
||||
<entry>demote</entry>
|
||||
<entry><p>TODO</p></entry>
|
||||
<entry><para>TODO</para></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
@@ -1451,7 +1451,7 @@
|
||||
write-lock requests exist, this lock will not
|
||||
be granted until at least one of the write-locks
|
||||
is granted and released.
|
||||
<p>TODO: try-lock, timed-lock.</p>
|
||||
<para>TODO: try-lock, timed-lock.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
@@ -1464,7 +1464,7 @@
|
||||
exist, exactly one read-lock request will be
|
||||
granted before the next write-lock is granted.
|
||||
</para>
|
||||
<p>TODO: try-lock, timed-lock.</p>
|
||||
<para>TODO: try-lock, timed-lock.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
@@ -1485,7 +1485,7 @@
|
||||
in accordance with the intra-class
|
||||
scheduling policy.</para></entry>
|
||||
|
||||
<p>TODO: try-lock, timed-lock.</p>
|
||||
<para>TODO: try-lock, timed-lock.</para>
|
||||
</row>
|
||||
<row>
|
||||
<entry>write-locked</entry>
|
||||
@@ -1498,18 +1498,18 @@
|
||||
released. If other write-lock requests exist,
|
||||
this lock will be granted in accordance with
|
||||
the intra-class scheduling policy.
|
||||
<p>TODO: try-lock, timed-lock.</p>
|
||||
<para>TODO: try-lock, timed-lock.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>read-locked</entry>
|
||||
<entry>promote</entry>
|
||||
<entry><p>TODO</p></entry>
|
||||
<entry><para>TODO</para></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>write-locked</entry>
|
||||
<entry>demote</entry>
|
||||
<entry><p>TODO</p></entry>
|
||||
<entry><para>TODO</para></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
@@ -1553,7 +1553,7 @@
|
||||
requirements and constructed for the ReadWriteMutex object.</para>
|
||||
|
||||
<para>A ReadWriteMutex is
|
||||
<ulink url="../../utility/utility.htm#Class%20noncopyable">NonCopyable</ulink>.
|
||||
<ulink url="../../libs/utility/utility.htm#Class%20noncopyable">NonCopyable</ulink>.
|
||||
</para>
|
||||
|
||||
<para>For a ReadWriteMutex type <code>M</code>,
|
||||
|
||||
8
doc/index.html
Normal file
8
doc/index.html
Normal file
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="refresh" content="0; URL=../../../doc/html/threads.html">
|
||||
</head>
|
||||
<body>
|
||||
Automatic redirection failed, please go to <a href="../../../doc/html/threads.html">../../../doc/html/threads.html</a>
|
||||
</body>
|
||||
</html>
|
||||
@@ -32,7 +32,7 @@ xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
<librarycategory name="category:concurrent" />
|
||||
<title>Boost.Threads</title>
|
||||
</libraryinfo>
|
||||
<title>&Boost.Threads;</title>
|
||||
<title>Boost.Threads</title>
|
||||
<xi:include href="overview.xml"/>
|
||||
<xi:include href="design.xml"/>
|
||||
<xi:include href="concepts.xml"/>
|
||||
|
||||
@@ -17,54 +17,50 @@
|
||||
// insist on threading support being available:
|
||||
#include <boost/config/requires_threads.hpp>
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
# if defined(BOOST_THREAD_BUILD_DLL) //Build dll
|
||||
# define BOOST_THREAD_DECL __declspec(dllexport)
|
||||
# elif defined(BOOST_THREAD_BUILD_LIB) //Build lib
|
||||
# define BOOST_THREAD_DECL
|
||||
# elif defined(BOOST_THREAD_USE_DLL) //Use dll
|
||||
# define BOOST_THREAD_DECL __declspec(dllimport)
|
||||
# define BOOST_DYN_LINK
|
||||
# elif defined(BOOST_THREAD_USE_LIB) //Use lib
|
||||
# define BOOST_THREAD_DECL
|
||||
# else //Use default
|
||||
#if defined(BOOST_THREAD_BUILD_DLL) //Build dll
|
||||
#elif defined(BOOST_THREAD_BUILD_LIB) //Build lib
|
||||
#elif defined(BOOST_THREAD_USE_DLL) //Use dll
|
||||
#elif defined(BOOST_THREAD_USE_LIB) //Use lib
|
||||
#else //Use default
|
||||
# if defined(BOOST_HAS_WINTHREADS)
|
||||
# if defined(BOOST_MSVC) || defined(BOOST_INTEL_WIN)
|
||||
//For VC++, choose according to threading library setting
|
||||
# if defined(_DLL)
|
||||
//Threading library is dll: use Boost.Threads dll
|
||||
# define BOOST_THREAD_USE_DLL
|
||||
# define BOOST_THREAD_DECL __declspec(dllimport)
|
||||
# define BOOST_DYN_LINK
|
||||
# else
|
||||
//Threading library is lib: used Boost.Threads lib
|
||||
# define BOOST_THREAD_USE_LIB
|
||||
# define BOOST_THREAD_DECL
|
||||
# endif
|
||||
//For compilers supporting auto-tss cleanup
|
||||
//with Boost.Threads lib, use Boost.Threads lib
|
||||
# define BOOST_THREAD_USE_LIB
|
||||
# else
|
||||
//For compilers not yet supporting auto-tss cleanup
|
||||
//with Boost.Threads lib, use Boost.Threads dll
|
||||
# define BOOST_THREAD_USE_DLL
|
||||
# define BOOST_THREAD_DECL __declspec(dllimport)
|
||||
# define BOOST_DYN_LINK
|
||||
# endif
|
||||
# else
|
||||
# define BOOST_THREAD_USE_LIB
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_HAS_DECLSPEC)
|
||||
# if defined(BOOST_THREAD_BUILD_DLL) //Build dll
|
||||
# define BOOST_THREAD_DECL __declspec(dllexport)
|
||||
# elif defined(BOOST_THREAD_USE_DLL) //Use dll
|
||||
# define BOOST_THREAD_DECL __declspec(dllimport)
|
||||
# else
|
||||
# define BOOST_THREAD_DECL
|
||||
# endif
|
||||
#else
|
||||
# define BOOST_THREAD_DECL
|
||||
# if defined(BOOST_THREAD_USE_LIB) //Use dll
|
||||
# define BOOST_THREAD_USE_DLL
|
||||
# define BOOST_DYN_LINK
|
||||
# elif defined(BOOST_THREAD_USE_DLL) //Use lib
|
||||
# define BOOST_THREAD_USE_LIB
|
||||
# else //Use default
|
||||
# define BOOST_THREAD_USE_LIB
|
||||
# endif
|
||||
#endif // BOOST_HAS_WINTHREADS
|
||||
#endif // BOOST_HAS_DECLSPEC
|
||||
|
||||
//
|
||||
// Automatically link to the correct build variant where possible.
|
||||
//
|
||||
#if !defined(BOOST_ALL_NO_LIB) && !defined(BOOST_THREAD_NO_LIB) && !defined(BOOST_THREAD_BUILD_DLL) && !defined(BOOST_THREAD_BUILD_LIB)
|
||||
//
|
||||
// Tell the autolink to link dynamically, this will get undef'ed by auto_link.hpp
|
||||
// once it's done with it:
|
||||
//
|
||||
#if defined(BOOST_THREAD_USE_DLL)
|
||||
# define BOOST_DYN_LINK
|
||||
#endif
|
||||
//
|
||||
// Set the name of our library, this will get undef'ed by auto_link.hpp
|
||||
// once it's done with it:
|
||||
//
|
||||
@@ -82,3 +78,9 @@
|
||||
#endif // auto-linking disabled
|
||||
|
||||
#endif // BOOST_THREAD_CONFIG_WEK1032003_HPP
|
||||
|
||||
// Change Log:
|
||||
// 22 Jan 05 Roland Schwarz (speedsnail)
|
||||
// Usage of BOOST_HAS_DECLSPEC macro.
|
||||
// Default again is static lib usage.
|
||||
// BOOST_DYN_LINK only defined when autolink included.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright (C) 2002-2003
|
||||
// David Moore
|
||||
// David Moore, Michael Glassford
|
||||
//
|
||||
// Original scoped_lock implementation
|
||||
// Copyright (C) 2001
|
||||
@@ -174,7 +174,7 @@ public:
|
||||
m_state = read_write_lock_state::write_locked;
|
||||
}
|
||||
|
||||
//If allow_unlock = true, set_lock always succeedes and
|
||||
//If allow_unlock = true, set_lock always succeeds and
|
||||
//the function result indicates whether an unlock was required.
|
||||
//If allow_unlock = false, set_lock may fail;
|
||||
//the function result indicates whether it succeeded.
|
||||
@@ -448,7 +448,7 @@ public:
|
||||
return read_write_lock_ops<TryReadWriteMutex>::try_promote(m_mutex) ? (m_state = read_write_lock_state::write_locked, true) : false;
|
||||
}
|
||||
|
||||
//If allow_unlock = true, set_lock always succeedes and
|
||||
//If allow_unlock = true, set_lock always succeeds and
|
||||
//the function result indicates whether an unlock was required.
|
||||
//If allow_unlock = false, set_lock may fail;
|
||||
//the function result indicates whether it succeeded.
|
||||
@@ -806,7 +806,7 @@ public:
|
||||
return read_write_lock_ops<TimedReadWriteMutex>::timed_promote(m_mutex, xt) ? (m_state = read_write_lock_state::write_locked, true) : false;
|
||||
}
|
||||
|
||||
//If allow_unlock = true, set_lock always succeedes and
|
||||
//If allow_unlock = true, set_lock always succeeds and
|
||||
//the function result indicates whether an unlock was required.
|
||||
//If allow_unlock = false, set_lock may fail;
|
||||
//the function result indicates whether it succeeded.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright (C) 2002-2003
|
||||
// David Moore, William E. Kempf
|
||||
// David Moore, William E. Kempf, Michael Glassford
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/detail/workaround.hpp>
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/detail/lock.hpp>
|
||||
@@ -33,7 +34,7 @@ namespace read_write_scheduling_policy {
|
||||
writer_priority, //Prefer writers; can starve readers
|
||||
reader_priority, //Prefer readers; can starve writers
|
||||
alternating_many_reads, //Alternate readers and writers; before a writer, release all queued readers
|
||||
alternating_single_read //Alternate readers and writers; before a writer, release only on queued reader
|
||||
alternating_single_read //Alternate readers and writers; before a writer, release only one queued reader
|
||||
};
|
||||
} // namespace read_write_scheduling_policy
|
||||
|
||||
@@ -51,27 +52,28 @@ struct read_write_mutex_impl
|
||||
typedef detail::thread::scoped_try_lock<Mutex> scoped_try_lock;
|
||||
typedef detail::thread::scoped_timed_lock<Mutex> scoped_timed_lock;
|
||||
|
||||
read_write_mutex_impl(read_write_scheduling_policy::read_write_scheduling_policy_enum sp)
|
||||
: m_num_waiting_writers(0),
|
||||
m_num_waiting_readers(0),
|
||||
m_num_readers_to_wake(0),
|
||||
m_state_waiting_promotion(false),
|
||||
m_state(0),
|
||||
m_sp(sp),
|
||||
m_readers_next(true) { }
|
||||
read_write_mutex_impl(read_write_scheduling_policy::read_write_scheduling_policy_enum sp);
|
||||
#if !BOOST_WORKAROUND(__BORLANDC__,<= 0x564)
|
||||
~read_write_mutex_impl();
|
||||
#endif
|
||||
|
||||
Mutex m_prot;
|
||||
|
||||
const read_write_scheduling_policy::read_write_scheduling_policy_enum m_sp;
|
||||
int m_state; //-1 = write lock; 0 = unlocked; >0 = read locked
|
||||
|
||||
boost::condition m_waiting_writers;
|
||||
boost::condition m_waiting_readers;
|
||||
boost::condition m_waiting_promotion;
|
||||
int m_num_waiting_writers;
|
||||
int m_num_waiting_readers;
|
||||
int m_num_readers_to_wake;
|
||||
boost::condition m_waiting_promotion;
|
||||
bool m_state_waiting_promotion;
|
||||
int m_state; // -1 = excl locked
|
||||
// 0 = unlocked
|
||||
// 1-> INT_MAX - shared locked
|
||||
const read_write_scheduling_policy::read_write_scheduling_policy_enum m_sp;
|
||||
|
||||
int m_num_waking_writers;
|
||||
int m_num_waking_readers;
|
||||
int m_num_max_waking_writers; //Debug only
|
||||
int m_num_max_waking_readers; //Debug only
|
||||
|
||||
bool m_readers_next;
|
||||
|
||||
void do_read_lock();
|
||||
@@ -96,12 +98,20 @@ struct read_write_mutex_impl
|
||||
|
||||
private:
|
||||
|
||||
void do_unlock_scheduling_impl();
|
||||
void do_timeout_scheduling_impl();
|
||||
void do_demote_scheduling_impl();
|
||||
void do_scheduling_impl();
|
||||
|
||||
bool do_demote_to_read_lock_impl();
|
||||
|
||||
enum scheduling_reason
|
||||
{
|
||||
scheduling_reason_unlock,
|
||||
scheduling_reason_timeout,
|
||||
scheduling_reason_demote
|
||||
};
|
||||
|
||||
void do_scheduling_impl(const scheduling_reason reason);
|
||||
bool do_wake_one_reader(void);
|
||||
bool do_wake_all_readers(void);
|
||||
bool do_wake_writer(void);
|
||||
bool waker_exists(void);
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
@@ -112,8 +122,8 @@ class BOOST_THREAD_DECL read_write_mutex : private noncopyable
|
||||
{
|
||||
public:
|
||||
|
||||
read_write_mutex(read_write_scheduling_policy::read_write_scheduling_policy_enum sp) : m_impl(sp) { }
|
||||
~read_write_mutex() { }
|
||||
read_write_mutex(read_write_scheduling_policy::read_write_scheduling_policy_enum sp);
|
||||
~read_write_mutex();
|
||||
|
||||
read_write_scheduling_policy::read_write_scheduling_policy_enum policy() const { return m_impl.m_sp; }
|
||||
|
||||
@@ -151,8 +161,8 @@ class BOOST_THREAD_DECL try_read_write_mutex : private noncopyable
|
||||
{
|
||||
public:
|
||||
|
||||
try_read_write_mutex(read_write_scheduling_policy::read_write_scheduling_policy_enum sp) : m_impl(sp) { }
|
||||
~try_read_write_mutex() { }
|
||||
try_read_write_mutex(read_write_scheduling_policy::read_write_scheduling_policy_enum sp);
|
||||
~try_read_write_mutex();
|
||||
|
||||
read_write_scheduling_policy::read_write_scheduling_policy_enum policy() const { return m_impl.m_sp; }
|
||||
|
||||
@@ -201,8 +211,8 @@ class BOOST_THREAD_DECL timed_read_write_mutex : private noncopyable
|
||||
{
|
||||
public:
|
||||
|
||||
timed_read_write_mutex(read_write_scheduling_policy::read_write_scheduling_policy_enum sp) : m_impl(sp) { }
|
||||
~timed_read_write_mutex() { }
|
||||
timed_read_write_mutex(read_write_scheduling_policy::read_write_scheduling_policy_enum sp);
|
||||
~timed_read_write_mutex();
|
||||
|
||||
read_write_scheduling_policy::read_write_scheduling_policy_enum policy() const { return m_impl.m_sp; }
|
||||
|
||||
|
||||
@@ -70,6 +70,7 @@ public:
|
||||
void add_thread(thread* thrd);
|
||||
void remove_thread(thread* thrd);
|
||||
void join_all();
|
||||
int size();
|
||||
|
||||
private:
|
||||
std::list<thread*> m_threads;
|
||||
|
||||
@@ -11,11 +11,17 @@
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/detail/workaround.hpp>
|
||||
|
||||
#include <boost/thread/once.hpp>
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
# if BOOST_WORKAROUND(__BORLANDC__,<= 0x551)
|
||||
using std::size_t;
|
||||
# endif
|
||||
# include <windows.h>
|
||||
# if defined(BOOST_NO_STRINGSTREAM)
|
||||
# include <strstream>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -519,7 +519,7 @@ bool recursive_try_mutex::do_trylock()
|
||||
# if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
|
||||
int res = 0;
|
||||
res = pthread_mutex_trylock(&m_mutex);
|
||||
assert(res == 0);
|
||||
assert(res == 0 || res == EBUSY);
|
||||
|
||||
if (res == 0)
|
||||
{
|
||||
|
||||
@@ -220,6 +220,7 @@ bool thread::operator!=(const thread& other) const
|
||||
|
||||
void thread::join()
|
||||
{
|
||||
assert(m_joinable); //See race condition comment below
|
||||
int res = 0;
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_thread), INFINITE);
|
||||
@@ -367,4 +368,9 @@ void thread_group::join_all()
|
||||
}
|
||||
}
|
||||
|
||||
int thread_group::size()
|
||||
{
|
||||
return m_threads.size();
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
|
||||
@@ -27,7 +27,7 @@ inline void to_time(int milliseconds, boost::xtime& xt)
|
||||
xt.nsec += ((milliseconds % MILLISECONDS_PER_SECOND) *
|
||||
NANOSECONDS_PER_MILLISECOND);
|
||||
|
||||
if (xt.nsec > NANOSECONDS_PER_SECOND)
|
||||
if (xt.nsec >= NANOSECONDS_PER_SECOND)
|
||||
{
|
||||
++xt.sec;
|
||||
xt.nsec -= NANOSECONDS_PER_SECOND;
|
||||
@@ -39,7 +39,7 @@ inline void to_timespec(const boost::xtime& xt, timespec& ts)
|
||||
{
|
||||
ts.tv_sec = static_cast<int>(xt.sec);
|
||||
ts.tv_nsec = static_cast<int>(xt.nsec);
|
||||
if(ts.tv_nsec > NANOSECONDS_PER_SECOND)
|
||||
if(ts.tv_nsec >= NANOSECONDS_PER_SECOND)
|
||||
{
|
||||
ts.tv_sec += ts.tv_nsec / NANOSECONDS_PER_SECOND;
|
||||
ts.tv_nsec %= NANOSECONDS_PER_SECOND;
|
||||
@@ -75,7 +75,7 @@ inline void to_timespec_duration(const boost::xtime& xt, timespec& ts)
|
||||
ts.tv_sec -= 1;
|
||||
ts.tv_nsec += NANOSECONDS_PER_SECOND;
|
||||
}
|
||||
if(ts.tv_nsec > NANOSECONDS_PER_SECOND)
|
||||
if(ts.tv_nsec >= NANOSECONDS_PER_SECOND)
|
||||
{
|
||||
ts.tv_sec += ts.tv_nsec / NANOSECONDS_PER_SECOND;
|
||||
ts.tv_nsec %= NANOSECONDS_PER_SECOND;
|
||||
|
||||
@@ -95,7 +95,7 @@ int xtime_get(struct xtime* xtp, int clock_type)
|
||||
# endif
|
||||
static const boost::uint64_t TIMESPEC_TO_FILETIME_OFFSET =
|
||||
UINT64_C(116444736000000000);
|
||||
|
||||
|
||||
const boost::uint64_t ft64 =
|
||||
(static_cast<boost::uint64_t>(ft.dwHighDateTime) << 32)
|
||||
+ ft.dwLowDateTime;
|
||||
|
||||
@@ -19,18 +19,27 @@
|
||||
import testing ;
|
||||
|
||||
project
|
||||
: requirements <library>../build//boost_thread
|
||||
<library>../../test/build//boost_unit_test_framework
|
||||
: requirements <library>../../test/build//boost_unit_test_framework
|
||||
<threading>multi
|
||||
;
|
||||
|
||||
rule thread-run ( sources )
|
||||
{
|
||||
return
|
||||
[ run $(sources) ../build//boost_thread ]
|
||||
[ run $(sources) ../build//boost_thread/<link>static
|
||||
: : : : $(sources[1]:B)_lib ]
|
||||
;
|
||||
}
|
||||
|
||||
{
|
||||
test-suite "threads"
|
||||
: [ run test_thread.cpp ]
|
||||
[ run test_mutex.cpp ]
|
||||
[ run test_condition.cpp ]
|
||||
[ run test_tss.cpp ]
|
||||
[ run test_once.cpp ]
|
||||
[ run test_xtime.cpp ]
|
||||
[ run test_barrier.cpp ]
|
||||
: [ thread-run test_thread.cpp ]
|
||||
[ thread-run test_mutex.cpp ]
|
||||
[ thread-run test_condition.cpp ]
|
||||
[ thread-run test_tss.cpp ]
|
||||
[ thread-run test_once.cpp ]
|
||||
[ thread-run test_xtime.cpp ]
|
||||
[ thread-run test_barrier.cpp ]
|
||||
;
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ void test_barrier()
|
||||
|
||||
g.join_all();
|
||||
|
||||
BOOST_TEST(global_parameter == 5);
|
||||
BOOST_CHECK(global_parameter == 5);
|
||||
}
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#include <boost/thread/condition.hpp>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/test/unit_test_suite_ex.hpp>
|
||||
|
||||
#define DEFAULT_EXECUTION_MONITOR_TYPE execution_monitor::use_sleep_only
|
||||
#include <libs/thread/test/util.inl>
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
// 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/thread/thread.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <boost/thread/read_write_mutex.hpp>
|
||||
@@ -17,314 +19,767 @@
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#define TS_CHECK(pred) \
|
||||
do { if (!(pred)) BOOST_ERROR (#pred); } while (0)
|
||||
#define TS_CHECK_MSG(pred, msg) \
|
||||
do { if (!(pred)) BOOST_ERROR (msg); } while (0)
|
||||
|
||||
namespace {
|
||||
|
||||
int shared_val = 0;
|
||||
|
||||
boost::xtime xsecs(int secs)
|
||||
{
|
||||
//Create an xtime that is secs seconds from now
|
||||
boost::xtime ret;
|
||||
BOOST_TEST(boost::TIME_UTC == boost::xtime_get(&ret, boost::TIME_UTC));
|
||||
TS_CHECK (boost::TIME_UTC == boost::xtime_get(&ret, boost::TIME_UTC));
|
||||
ret.sec += secs;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define MESSAGE "w1=" << w1.value_ << ", w2=" << w2.value_ << ", r1=" << r1.value_ << ", r2=" << r2.value_
|
||||
|
||||
template <typename RW>
|
||||
class thread_adapter
|
||||
{
|
||||
public:
|
||||
thread_adapter(void (*func)(void*,RW &), void* param1,RW ¶m2)
|
||||
: _func(func), _param1(param1) ,_param2(param2){ }
|
||||
void operator()() const { _func(_param1, _param2); }
|
||||
|
||||
thread_adapter(
|
||||
void (*func)(void*, RW&),
|
||||
void* param1,
|
||||
RW ¶m2
|
||||
)
|
||||
: func_(func)
|
||||
, param1_(param1)
|
||||
, param2_(param2)
|
||||
{}
|
||||
|
||||
void operator()() const
|
||||
{
|
||||
func_(param1_, param2_);
|
||||
}
|
||||
|
||||
private:
|
||||
void (*_func)(void*, RW &);
|
||||
void* _param1;
|
||||
RW& _param2;
|
||||
|
||||
void (*func_)(void*, RW&);
|
||||
void* param1_;
|
||||
RW& param2_;
|
||||
};
|
||||
|
||||
const int k_data_init = -1;
|
||||
|
||||
template <typename RW>
|
||||
struct data
|
||||
{
|
||||
data(int id, RW &m, int secs=0)
|
||||
: m_id(id), m_value(-1), m_secs(secs), m_rw(m)
|
||||
{
|
||||
}
|
||||
int m_id;
|
||||
int m_value;
|
||||
int m_secs;
|
||||
data(
|
||||
int id,
|
||||
RW& m,
|
||||
int wait_for_lock_secs,
|
||||
int sleep_with_lock_secs,
|
||||
bool demote_after_write = false
|
||||
)
|
||||
: id_(id)
|
||||
, wait_for_lock_secs_(wait_for_lock_secs)
|
||||
, sleep_with_lock_secs_(sleep_with_lock_secs)
|
||||
, test_promotion_and_demotion_(demote_after_write)
|
||||
, value_(k_data_init)
|
||||
, rw_(m)
|
||||
{}
|
||||
|
||||
RW& m_rw; // Reader/Writer mutex
|
||||
int id_;
|
||||
int wait_for_lock_secs_;
|
||||
int sleep_with_lock_secs_;
|
||||
bool test_promotion_and_demotion_;
|
||||
int value_;
|
||||
|
||||
RW& rw_;
|
||||
};
|
||||
|
||||
// plain_writer excercises the "infinite" lock for each
|
||||
// read_write_mutex type.
|
||||
|
||||
template<typename RW>
|
||||
void plain_writer(void *arg,RW &rw)
|
||||
void plain_writer(void* arg, RW& rw)
|
||||
{
|
||||
data<RW> *pdata = (data<RW> *) arg;
|
||||
// std::cout << "-->W" << pdata->m_id << "\n";
|
||||
|
||||
typename RW::scoped_read_write_lock l(rw, boost::read_write_lock_state::write_locked);
|
||||
|
||||
boost::thread::sleep(xsecs(3));
|
||||
shared_val += 10;
|
||||
|
||||
pdata->m_value = shared_val;
|
||||
}
|
||||
|
||||
template<typename RW>
|
||||
void plain_reader(void *arg,RW &rw)
|
||||
{
|
||||
data<RW> *pdata = (data<RW> *) arg;
|
||||
typename RW::scoped_read_write_lock l(rw, boost::read_write_lock_state::read_locked);
|
||||
|
||||
pdata->m_value = shared_val;
|
||||
}
|
||||
|
||||
template<typename RW>
|
||||
void try_writer(void *arg,RW &rw)
|
||||
{
|
||||
data<RW> *pdata = (data<RW> *) arg;
|
||||
// std::cout << "-->W" << pdata->m_id << "\n";
|
||||
|
||||
typename RW::scoped_try_read_write_lock l(rw, boost::read_write_lock_state::unlocked);
|
||||
|
||||
if (l.try_write_lock())
|
||||
try
|
||||
{
|
||||
data<RW>* pdata = (data<RW>*) arg;
|
||||
TS_CHECK_MSG(pdata->wait_for_lock_secs_ == 0, "pdata->wait_for_lock_secs_: " << pdata->wait_for_lock_secs_);
|
||||
|
||||
boost::thread::sleep(xsecs(3));
|
||||
shared_val += 10;
|
||||
typename RW::scoped_read_write_lock l(
|
||||
rw,
|
||||
pdata->test_promotion_and_demotion_
|
||||
? boost::read_write_lock_state::read_locked
|
||||
: boost::read_write_lock_state::write_locked
|
||||
);
|
||||
|
||||
pdata->m_value = shared_val;
|
||||
bool succeeded = true;
|
||||
|
||||
if (pdata->test_promotion_and_demotion_)
|
||||
{
|
||||
try
|
||||
{
|
||||
l.promote();
|
||||
}
|
||||
catch(const boost::lock_error&)
|
||||
{
|
||||
succeeded = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (succeeded)
|
||||
{
|
||||
if (pdata->sleep_with_lock_secs_ > 0)
|
||||
boost::thread::sleep(xsecs(pdata->sleep_with_lock_secs_));
|
||||
|
||||
shared_val += 10;
|
||||
|
||||
if (pdata->test_promotion_and_demotion_)
|
||||
l.demote();
|
||||
|
||||
pdata->value_ = shared_val;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<typename RW>
|
||||
void try_reader(void *arg,RW &rw)
|
||||
{
|
||||
data<RW> *pdata = (data<RW> *) arg;
|
||||
typename RW::scoped_try_read_write_lock l(rw, boost::read_write_lock_state::unlocked);
|
||||
|
||||
if (l.try_read_lock())
|
||||
catch(...)
|
||||
{
|
||||
pdata->m_value = shared_val;
|
||||
TS_CHECK_MSG(false, "plain_writer() exception!");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename RW>
|
||||
void timed_writer(void *arg,RW &rw)
|
||||
void plain_reader(void* arg, RW& rw)
|
||||
{
|
||||
data<RW> *pdata = (data<RW> *) arg;
|
||||
|
||||
boost::xtime xt;
|
||||
xt = xsecs(pdata->m_secs);
|
||||
typename RW::scoped_timed_read_write_lock l(rw,boost::read_write_lock_state::unlocked);
|
||||
|
||||
if (l.timed_write_lock(xt))
|
||||
try
|
||||
{
|
||||
boost::thread::sleep(xsecs(3));
|
||||
shared_val += 10;
|
||||
data<RW>* pdata = (data<RW>*)arg;
|
||||
TS_CHECK(!pdata->test_promotion_and_demotion_);
|
||||
TS_CHECK_MSG(pdata->wait_for_lock_secs_ == 0, "pdata->wait_for_lock_secs_: " << pdata->wait_for_lock_secs_);
|
||||
|
||||
pdata->m_value = shared_val;
|
||||
typename RW::scoped_read_write_lock l(rw, boost::read_write_lock_state::read_locked);
|
||||
|
||||
if (pdata->sleep_with_lock_secs_ > 0)
|
||||
boost::thread::sleep(xsecs(pdata->sleep_with_lock_secs_));
|
||||
|
||||
pdata->value_ = shared_val;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
TS_CHECK_MSG(false, "plain_reader() exception!");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename RW>
|
||||
void timed_reader(void *arg,RW &rw)
|
||||
void try_writer(void* arg, RW& rw)
|
||||
{
|
||||
data<RW> *pdata = (data<RW> *) arg;
|
||||
boost::xtime xt;
|
||||
xt = xsecs(pdata->m_secs);
|
||||
|
||||
typename RW::scoped_timed_read_write_lock l(rw,boost::read_write_lock_state::unlocked);
|
||||
|
||||
if (l.timed_read_lock(xt))
|
||||
try
|
||||
{
|
||||
pdata->m_value = shared_val;
|
||||
data<RW>* pdata = (data<RW>*) arg;
|
||||
TS_CHECK_MSG(pdata->wait_for_lock_secs_ == 0, "pdata->wait_for_lock_secs_: " << pdata->wait_for_lock_secs_);
|
||||
|
||||
typename RW::scoped_try_read_write_lock l(rw, boost::read_write_lock_state::unlocked);
|
||||
|
||||
bool succeeded = false;
|
||||
|
||||
if (pdata->test_promotion_and_demotion_)
|
||||
succeeded = l.try_read_lock() && l.try_promote();
|
||||
else
|
||||
succeeded = l.try_write_lock();
|
||||
|
||||
if (succeeded)
|
||||
{
|
||||
if (pdata->sleep_with_lock_secs_ > 0)
|
||||
boost::thread::sleep(xsecs(pdata->sleep_with_lock_secs_));
|
||||
|
||||
shared_val += 10;
|
||||
|
||||
if (pdata->test_promotion_and_demotion_)
|
||||
l.demote();
|
||||
|
||||
pdata->value_ = shared_val;
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
TS_CHECK_MSG(false, "try_writer() exception!");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename RW>
|
||||
void dump_times(const char *prefix,data<RW> *pdata)
|
||||
void try_reader(void*arg, RW& rw)
|
||||
{
|
||||
std::cout << " " << prefix << pdata->m_id <<
|
||||
" In:" << pdata->m_start.LowPart <<
|
||||
" Holding:" << pdata->m_holding.LowPart <<
|
||||
" Out: " << pdata->m_end.LowPart << std::endl;
|
||||
try
|
||||
{
|
||||
data<RW>* pdata = (data<RW>*)arg;
|
||||
TS_CHECK(!pdata->test_promotion_and_demotion_);
|
||||
TS_CHECK_MSG(pdata->wait_for_lock_secs_ == 0, "pdata->wait_for_lock_secs_: " << pdata->wait_for_lock_secs_);
|
||||
|
||||
typename RW::scoped_try_read_write_lock l(rw, boost::read_write_lock_state::unlocked);
|
||||
|
||||
if (l.try_read_lock())
|
||||
{
|
||||
if (pdata->sleep_with_lock_secs_ > 0)
|
||||
boost::thread::sleep(xsecs(pdata->sleep_with_lock_secs_));
|
||||
|
||||
pdata->value_ = shared_val;
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
TS_CHECK_MSG(false, "try_reader() exception!");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename RW>
|
||||
void test_plain_read_write_mutex(RW &rw)
|
||||
void timed_writer(void* arg, RW& rw)
|
||||
{
|
||||
try
|
||||
{
|
||||
data<RW>* pdata = (data<RW>*)arg;
|
||||
|
||||
typename RW::scoped_timed_read_write_lock l(rw, boost::read_write_lock_state::unlocked);
|
||||
|
||||
bool succeeded = false;
|
||||
|
||||
boost::xtime xt = xsecs(pdata->wait_for_lock_secs_);
|
||||
if (pdata->test_promotion_and_demotion_)
|
||||
succeeded = l.timed_read_lock(xt) && l.timed_promote(xt);
|
||||
else
|
||||
succeeded = l.timed_write_lock(xt);
|
||||
|
||||
if (succeeded)
|
||||
{
|
||||
if (pdata->sleep_with_lock_secs_ > 0)
|
||||
boost::thread::sleep(xsecs(pdata->sleep_with_lock_secs_));
|
||||
|
||||
shared_val += 10;
|
||||
|
||||
if (pdata->test_promotion_and_demotion_)
|
||||
l.demote();
|
||||
|
||||
pdata->value_ = shared_val;
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
TS_CHECK_MSG(false, "timed_writer() exception!");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename RW>
|
||||
void timed_reader(void* arg, RW& rw)
|
||||
{
|
||||
try
|
||||
{
|
||||
data<RW>* pdata = (data<RW>*)arg;
|
||||
TS_CHECK(!pdata->test_promotion_and_demotion_);
|
||||
|
||||
typename RW::scoped_timed_read_write_lock l(rw,boost::read_write_lock_state::unlocked);
|
||||
|
||||
boost::xtime xt = xsecs(pdata->wait_for_lock_secs_);
|
||||
if (l.timed_read_lock(xt))
|
||||
{
|
||||
if (pdata->sleep_with_lock_secs_ > 0)
|
||||
boost::thread::sleep(xsecs(pdata->sleep_with_lock_secs_));
|
||||
|
||||
pdata->value_ = shared_val;
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
TS_CHECK_MSG(false, "timed_reader() exception!");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename RW>
|
||||
void clear_data(data<RW>& data1, data<RW>& data2, data<RW>& data3, data<RW>& data4)
|
||||
{
|
||||
shared_val = 0;
|
||||
data<RW> r1(1,rw);
|
||||
data<RW> r2(2,rw);
|
||||
data<RW> w1(1,rw);
|
||||
data<RW> w2(2,rw);
|
||||
data1.value_ = k_data_init;
|
||||
data2.value_ = k_data_init;
|
||||
data3.value_ = k_data_init;
|
||||
data4.value_ = k_data_init;
|
||||
}
|
||||
|
||||
// Writer one launches, holds the lock for 3 seconds.
|
||||
boost::thread tw1(thread_adapter<RW>(plain_writer,&w1,rw));
|
||||
bool shared_test_writelocked = false;
|
||||
bool shared_test_readlocked = false;
|
||||
bool shared_test_unlocked = false;
|
||||
|
||||
// Writer two launches, tries to grab the lock, "clearly"
|
||||
// after Writer one will already be holding it.
|
||||
boost::thread::sleep(xsecs(1));
|
||||
boost::thread tw2(thread_adapter<RW>(plain_writer,&w2,rw));
|
||||
|
||||
// Reader one launches, "clearly" after writer two, and "clearly"
|
||||
// while writer 1 still holds the lock
|
||||
boost::thread::sleep(xsecs(1));
|
||||
boost::thread tr1(thread_adapter<RW>(plain_reader,&r1,rw));
|
||||
boost::thread tr2(thread_adapter<RW>(plain_reader,&r2,rw));
|
||||
|
||||
tr2.join();
|
||||
tr1.join();
|
||||
tw2.join();
|
||||
tw1.join();
|
||||
|
||||
if (rw.policy() == boost::read_write_scheduling_policy::writer_priority)
|
||||
template<typename RW>
|
||||
void run_try_tests(void* arg, RW& rw)
|
||||
{
|
||||
try
|
||||
{
|
||||
BOOST_TEST(w1.m_value == 10);
|
||||
BOOST_TEST(w2.m_value == 20);
|
||||
BOOST_TEST(r1.m_value == 20); // Readers get in after 2nd writer
|
||||
BOOST_TEST(r2.m_value == 20);
|
||||
TS_CHECK(shared_test_writelocked || shared_test_readlocked || shared_test_unlocked);
|
||||
|
||||
typename RW::scoped_try_read_write_lock l(rw, boost::read_write_lock_state::unlocked);
|
||||
|
||||
if (shared_test_writelocked)
|
||||
{
|
||||
//Verify that write lock blocks other write locks
|
||||
TS_CHECK(!l.try_write_lock());
|
||||
|
||||
//Verify that write lock blocks read locks
|
||||
TS_CHECK(!l.try_read_lock());
|
||||
}
|
||||
else if (shared_test_readlocked)
|
||||
{
|
||||
//Verify that read lock blocks write locks
|
||||
TS_CHECK(!l.try_write_lock());
|
||||
|
||||
//Verify that read lock does not block other read locks
|
||||
TS_CHECK(l.try_read_lock());
|
||||
|
||||
//Verify that read lock blocks promotion
|
||||
TS_CHECK(!l.try_promote());
|
||||
}
|
||||
else if (shared_test_unlocked)
|
||||
{
|
||||
//Verify that unlocked does not blocks write locks
|
||||
TS_CHECK(l.try_write_lock());
|
||||
|
||||
//Verify that unlocked does not block demotion
|
||||
TS_CHECK(l.try_demote());
|
||||
|
||||
l.unlock();
|
||||
|
||||
//Verify that unlocked does not block read locks
|
||||
TS_CHECK(l.try_read_lock());
|
||||
|
||||
//Verify that unlocked does not block promotion
|
||||
TS_CHECK(l.try_promote());
|
||||
|
||||
l.unlock();
|
||||
}
|
||||
}
|
||||
else if (rw.policy() == boost::read_write_scheduling_policy::reader_priority)
|
||||
catch(...)
|
||||
{
|
||||
BOOST_TEST(w1.m_value == 10);
|
||||
BOOST_TEST(w2.m_value == 20);
|
||||
BOOST_TEST(r1.m_value == 10); // Readers get in before 2nd writer
|
||||
BOOST_TEST(r2.m_value == 10);
|
||||
}
|
||||
else if (rw.policy() == boost::read_write_scheduling_policy::alternating_many_reads)
|
||||
{
|
||||
BOOST_TEST(w1.m_value == 10);
|
||||
BOOST_TEST(w2.m_value == 20);
|
||||
BOOST_TEST(r1.m_value == 10); // Readers get in before 2nd writer
|
||||
BOOST_TEST(r2.m_value == 10);
|
||||
}
|
||||
else if (rw.policy() == boost::read_write_scheduling_policy::alternating_single_read)
|
||||
{
|
||||
BOOST_TEST(w1.m_value == 10);
|
||||
BOOST_TEST(w2.m_value == 20);
|
||||
|
||||
// One Reader gets in before 2nd writer, but we can't tell
|
||||
// which reader will "win", so just check their sum.
|
||||
BOOST_TEST((r1.m_value + r2.m_value == 30));
|
||||
TS_CHECK_MSG(false, "run_try_tests() exception!");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename RW>
|
||||
void test_try_read_write_mutex(RW &rw)
|
||||
void test_plain_read_write_mutex(RW& rw, bool test_promotion_and_demotion)
|
||||
{
|
||||
data<RW> r1(1,rw);
|
||||
data<RW> w1(2,rw);
|
||||
data<RW> w2(3,rw);
|
||||
//Verify that a write lock prevents both readers and writers from obtaining a lock
|
||||
{
|
||||
shared_val = 0;
|
||||
data<RW> r1(1, rw, 0, 0);
|
||||
data<RW> r2(2, rw, 0, 0);
|
||||
data<RW> w1(3, rw, 0, 0);
|
||||
data<RW> w2(4, rw, 0, 0);
|
||||
|
||||
// We start with some specialized tests for "try" behavior
|
||||
//Write-lock the mutex and queue up other readers and writers
|
||||
|
||||
shared_val = 0;
|
||||
typename RW::scoped_read_write_lock l(rw, boost::read_write_lock_state::write_locked);
|
||||
|
||||
// Writer one launches, holds the lock for 3 seconds.
|
||||
boost::thread tr1(thread_adapter<RW>(plain_reader, &r1, rw));
|
||||
boost::thread tr2(thread_adapter<RW>(plain_reader, &r2, rw));
|
||||
boost::thread tw1(thread_adapter<RW>(plain_writer, &w1, rw));
|
||||
boost::thread tw2(thread_adapter<RW>(plain_writer, &w2, rw));
|
||||
|
||||
boost::thread tw1(thread_adapter<RW>(try_writer,&w1,rw));
|
||||
boost::thread::sleep(xsecs(1));
|
||||
|
||||
// Reader one launches, "clearly" after writer #1 holds the lock
|
||||
// and before it releases the lock.
|
||||
boost::thread::sleep(xsecs(1));
|
||||
boost::thread tr1(thread_adapter<RW>(try_reader,&r1,rw));
|
||||
//At this point, neither queued readers nor queued writers should have obtained access
|
||||
|
||||
// Writer two launches in the same timeframe.
|
||||
boost::thread tw2(thread_adapter<RW>(try_writer,&w2,rw));
|
||||
TS_CHECK_MSG(w1.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(w2.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(r1.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(r2.value_ == k_data_init, MESSAGE);
|
||||
|
||||
tw2.join();
|
||||
tr1.join();
|
||||
tw1.join();
|
||||
if (test_promotion_and_demotion)
|
||||
{
|
||||
l.demote();
|
||||
boost::thread::sleep(xsecs(1));
|
||||
//:boost::thread tr3(thread_adapter<RW>(plain_reader, &r3, rw));
|
||||
|
||||
BOOST_TEST(w1.m_value == 10);
|
||||
BOOST_TEST(r1.m_value == -1); // Try would return w/o waiting
|
||||
BOOST_TEST(w2.m_value == -1); // Try would return w/o waiting
|
||||
if (rw.policy() == boost::read_write_scheduling_policy::writer_priority)
|
||||
{
|
||||
//Expected result:
|
||||
//Since writers have priority, demotion doesn't release any readers.
|
||||
TS_CHECK_MSG(w1.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(w2.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(r1.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(r2.value_ == k_data_init, MESSAGE);
|
||||
}
|
||||
else if (rw.policy() == boost::read_write_scheduling_policy::reader_priority)
|
||||
{
|
||||
//Expected result:
|
||||
//Since readers have priority, demotion releases all readers.
|
||||
TS_CHECK_MSG(w1.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(w2.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(r1.value_ == 0, MESSAGE);
|
||||
TS_CHECK_MSG(r2.value_ == 0, MESSAGE);
|
||||
}
|
||||
else if (rw.policy() == boost::read_write_scheduling_policy::alternating_many_reads)
|
||||
{
|
||||
//Expected result:
|
||||
//Since readers can be released many at a time, demotion releases all queued readers.
|
||||
TS_CHECK_MSG(w1.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(w2.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(r1.value_ == 0, MESSAGE);
|
||||
TS_CHECK_MSG(r2.value_ == 0, MESSAGE);
|
||||
//:TS_CHECK_MSG(r3.value_ == k_data_init, MESSAGE);
|
||||
}
|
||||
else if (rw.policy() == boost::read_write_scheduling_policy::alternating_single_read)
|
||||
{
|
||||
//Expected result:
|
||||
//Since readers can be released only one at a time, demotion releases one queued reader.
|
||||
TS_CHECK_MSG(w1.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(w2.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(r1.value_ == k_data_init || r1.value_ == 0, MESSAGE);
|
||||
TS_CHECK_MSG(r2.value_ == k_data_init || r2.value_ == 0, MESSAGE);
|
||||
TS_CHECK_MSG(r1.value_ != r2.value_, MESSAGE);
|
||||
}
|
||||
}
|
||||
|
||||
l.unlock();
|
||||
|
||||
// We finish by repeating the plain tests with the try lock
|
||||
// This is important to verify that try locks are proper read_write_mutexes as
|
||||
// well.
|
||||
test_plain_read_write_mutex(rw);
|
||||
tr2.join();
|
||||
tr1.join();
|
||||
tw2.join();
|
||||
tw1.join();
|
||||
|
||||
if (rw.policy() == boost::read_write_scheduling_policy::writer_priority)
|
||||
{
|
||||
if (!test_promotion_and_demotion)
|
||||
{
|
||||
//Expected result:
|
||||
//1) either w1 or w2 obtains and releases the lock
|
||||
//2) the other of w1 and w2 obtains and releases the lock
|
||||
//3) r1 and r2 obtain and release the lock "simultaneously"
|
||||
TS_CHECK_MSG(w1.value_ == 10 || w1.value_ == 20, MESSAGE);
|
||||
TS_CHECK_MSG(w2.value_ == 10 || w2.value_ == 20, MESSAGE);
|
||||
TS_CHECK_MSG(w1.value_ != w2.value_, MESSAGE);
|
||||
TS_CHECK_MSG(r1.value_ == 20, MESSAGE);
|
||||
TS_CHECK_MSG(r2.value_ == 20, MESSAGE);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Expected result:
|
||||
//The same, except that either w1 or w2 (but not both) may
|
||||
//fail to promote to a write lock,
|
||||
//and r1, r2, or both may "sneak in" ahead of w1 and/or w2
|
||||
//by obtaining a read lock before w1 or w2 can promote
|
||||
//their initial read lock to a write lock.
|
||||
TS_CHECK_MSG(w1.value_ == k_data_init || w1.value_ == 10 || w1.value_ == 20, MESSAGE);
|
||||
TS_CHECK_MSG(w2.value_ == k_data_init || w2.value_ == 10 || w2.value_ == 20, MESSAGE);
|
||||
TS_CHECK_MSG(w1.value_ != w2.value_, MESSAGE);
|
||||
TS_CHECK_MSG(r1.value_ == k_data_init || r1.value_ == 10 || r1.value_ == 20, MESSAGE);
|
||||
TS_CHECK_MSG(r2.value_ == k_data_init || r2.value_ == 10 || r2.value_ == 20, MESSAGE);
|
||||
}
|
||||
}
|
||||
else if (rw.policy() == boost::read_write_scheduling_policy::reader_priority)
|
||||
{
|
||||
if (!test_promotion_and_demotion)
|
||||
{
|
||||
//Expected result:
|
||||
//1) r1 and r2 obtain and release the lock "simultaneously"
|
||||
//2) either w1 or w2 obtains and releases the lock
|
||||
//3) the other of w1 and w2 obtains and releases the lock
|
||||
TS_CHECK_MSG(w1.value_ == 10 || w1.value_ == 20, MESSAGE);
|
||||
TS_CHECK_MSG(w2.value_ == 10 || w2.value_ == 20, MESSAGE);
|
||||
TS_CHECK_MSG(w1.value_ != w2.value_, MESSAGE);
|
||||
TS_CHECK_MSG(r1.value_ == 0, MESSAGE);
|
||||
TS_CHECK_MSG(r2.value_ == 0, MESSAGE);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Expected result:
|
||||
//The same, except that either w1 or w2 (but not both) may
|
||||
//fail to promote to a write lock.
|
||||
TS_CHECK_MSG(w1.value_ == k_data_init || w1.value_ == 10 || w1.value_ == 20, MESSAGE);
|
||||
TS_CHECK_MSG(w2.value_ == k_data_init || w2.value_ == 10 || w2.value_ == 20, MESSAGE);
|
||||
TS_CHECK_MSG(w1.value_ != w2.value_, MESSAGE);
|
||||
TS_CHECK_MSG(r1.value_ == 0, MESSAGE);
|
||||
TS_CHECK_MSG(r2.value_ == 0, MESSAGE);
|
||||
}
|
||||
}
|
||||
else if (rw.policy() == boost::read_write_scheduling_policy::alternating_many_reads)
|
||||
{
|
||||
if (!test_promotion_and_demotion)
|
||||
{
|
||||
//Expected result:
|
||||
//1) r1 and r2 obtain and release the lock "simultaneously"
|
||||
//2) either w1 or w2 obtains and releases the lock
|
||||
//3) the other of w1 and w2 obtains and releases the lock
|
||||
TS_CHECK_MSG(w1.value_ == 10 || w1.value_ == 20, MESSAGE);
|
||||
TS_CHECK_MSG(w2.value_ == 10 || w2.value_ == 20, MESSAGE);
|
||||
TS_CHECK_MSG(w1.value_ != w2.value_, MESSAGE);
|
||||
TS_CHECK_MSG(r1.value_ == 0, MESSAGE);
|
||||
TS_CHECK_MSG(r2.value_ == 0, MESSAGE);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Expected result:
|
||||
//The same, except that either w1 or w2 (but not both) may
|
||||
//fail to promote to a write lock.
|
||||
TS_CHECK_MSG(w1.value_ == k_data_init || w1.value_ == 10 || w1.value_ == 20, MESSAGE);
|
||||
TS_CHECK_MSG(w2.value_ == k_data_init || w2.value_ == 10 || w2.value_ == 20, MESSAGE);
|
||||
TS_CHECK_MSG(w1.value_ != w2.value_, MESSAGE);
|
||||
TS_CHECK_MSG(r1.value_ == 0, MESSAGE);
|
||||
TS_CHECK_MSG(r2.value_ == 0, MESSAGE);
|
||||
}
|
||||
}
|
||||
else if (rw.policy() == boost::read_write_scheduling_policy::alternating_single_read)
|
||||
{
|
||||
if (!test_promotion_and_demotion)
|
||||
{
|
||||
//Expected result:
|
||||
//1) either r1 or r2 obtains and releases the lock
|
||||
//2) either w1 or w2 obtains and releases the lock
|
||||
//3) the other of r1 and r2 obtains and releases the lock
|
||||
//4) the other of w1 and w2 obtains and release the lock
|
||||
TS_CHECK_MSG(w1.value_ == 10 || w1.value_ == 20, MESSAGE);
|
||||
TS_CHECK_MSG(w2.value_ == 10 || w2.value_ == 20, MESSAGE);
|
||||
TS_CHECK_MSG(w1.value_ != w2.value_, MESSAGE);
|
||||
TS_CHECK_MSG(r1.value_ == 0 || r1.value_ == 10, MESSAGE);
|
||||
TS_CHECK_MSG(r2.value_ == 0 || r2.value_ == 10, MESSAGE);
|
||||
TS_CHECK_MSG(r1.value_ != r2.value_, MESSAGE);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Expected result:
|
||||
//Since w1 and w2 start as read locks, r1, r2, w1, and w2
|
||||
//obtain read locks "simultaneously". Each of w1 and w2,
|
||||
//after it obtain a read lock, attempts to promote to a
|
||||
//write lock; this attempt fails if the other has
|
||||
//already done so and currently holds the write lock;
|
||||
//otherwise it will succeed as soon as any other
|
||||
//read locks have been released.
|
||||
//In other words, any ordering is possible, and either
|
||||
//w1 or w2 (but not both) may fail to obtain the lock
|
||||
//altogether.
|
||||
TS_CHECK_MSG(w1.value_ == k_data_init || w1.value_ == 10 || w1.value_ == 20, MESSAGE);
|
||||
TS_CHECK_MSG(w2.value_ == k_data_init || w2.value_ == 10 || w2.value_ == 20, MESSAGE);
|
||||
TS_CHECK_MSG(w1.value_ != w2.value_, MESSAGE);
|
||||
TS_CHECK_MSG(r1.value_ == 0 || r1.value_ == 10 || r1.value_ == 20, MESSAGE);
|
||||
TS_CHECK_MSG(r2.value_ == 0 || r2.value_ == 10 || r2.value_ == 20, MESSAGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Verify that a read lock prevents readers but not writers from obtaining a lock
|
||||
{
|
||||
shared_val = 0;
|
||||
data<RW> r1(1, rw, 0, 0);
|
||||
data<RW> r2(2, rw, 0, 0);
|
||||
data<RW> w1(3, rw, 0, 0);
|
||||
data<RW> w2(4, rw, 0, 0);
|
||||
|
||||
//Read-lock the mutex and queue up other readers and writers
|
||||
|
||||
typename RW::scoped_read_write_lock l(rw, boost::read_write_lock_state::read_locked);
|
||||
|
||||
boost::thread tr1(thread_adapter<RW>(plain_reader, &r1, rw));
|
||||
boost::thread tr2(thread_adapter<RW>(plain_reader, &r2, rw));
|
||||
|
||||
boost::thread::sleep(xsecs(1));
|
||||
|
||||
boost::thread tw1(thread_adapter<RW>(plain_writer, &w1, rw));
|
||||
boost::thread tw2(thread_adapter<RW>(plain_writer, &w2, rw));
|
||||
|
||||
boost::thread::sleep(xsecs(1));
|
||||
|
||||
//Expected result: all readers passed through before the writers entered
|
||||
TS_CHECK_MSG(w1.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(w2.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(r1.value_ == 0, MESSAGE);
|
||||
TS_CHECK_MSG(r2.value_ == 0, MESSAGE);
|
||||
|
||||
if (test_promotion_and_demotion)
|
||||
{
|
||||
l.promote();
|
||||
}
|
||||
|
||||
l.unlock();
|
||||
|
||||
tr2.join();
|
||||
tr1.join();
|
||||
tw2.join();
|
||||
tw1.join();
|
||||
}
|
||||
|
||||
//Verify that a read lock prevents readers but not writers from obtaining a lock
|
||||
{
|
||||
shared_val = 0;
|
||||
data<RW> r1(1, rw, 0, 0);
|
||||
data<RW> r2(2, rw, 0, 0);
|
||||
data<RW> w1(3, rw, 0, 0);
|
||||
data<RW> w2(4, rw, 0, 0);
|
||||
|
||||
//Read-lock the mutex and queue up other readers and writers
|
||||
|
||||
typename RW::scoped_read_write_lock l(rw, boost::read_write_lock_state::read_locked);
|
||||
|
||||
boost::thread tw1(thread_adapter<RW>(plain_writer, &w1, rw));
|
||||
boost::thread tw2(thread_adapter<RW>(plain_writer, &w2, rw));
|
||||
|
||||
boost::thread::sleep(xsecs(1));
|
||||
|
||||
boost::thread tr1(thread_adapter<RW>(plain_reader, &r1, rw));
|
||||
boost::thread tr2(thread_adapter<RW>(plain_reader, &r2, rw));
|
||||
|
||||
boost::thread::sleep(xsecs(1));
|
||||
|
||||
if (rw.policy() == boost::read_write_scheduling_policy::writer_priority)
|
||||
{
|
||||
//Expected result:
|
||||
//Writers have priority, so no readers have been released
|
||||
TS_CHECK_MSG(w1.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(w2.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(r1.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(r2.value_ == k_data_init, MESSAGE);
|
||||
}
|
||||
else if (rw.policy() == boost::read_write_scheduling_policy::reader_priority)
|
||||
{
|
||||
//Expected result:
|
||||
//Readers have priority, so all readers have been released
|
||||
TS_CHECK_MSG(w1.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(w2.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(r1.value_ == 0, MESSAGE);
|
||||
TS_CHECK_MSG(r2.value_ == 0, MESSAGE);
|
||||
}
|
||||
else if (rw.policy() == boost::read_write_scheduling_policy::alternating_many_reads)
|
||||
{
|
||||
//Expected result:
|
||||
//It's the writers' turn, so no readers have been released
|
||||
TS_CHECK_MSG(w1.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(w2.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(r1.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(r2.value_ == k_data_init, MESSAGE);
|
||||
}
|
||||
else if (rw.policy() == boost::read_write_scheduling_policy::alternating_single_read)
|
||||
{
|
||||
//Expected result:
|
||||
//It's the writers' turn, so no readers have been released
|
||||
TS_CHECK_MSG(w1.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(w2.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(r1.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(r2.value_ == k_data_init, MESSAGE);
|
||||
}
|
||||
|
||||
if (test_promotion_and_demotion)
|
||||
{
|
||||
l.promote();
|
||||
}
|
||||
|
||||
l.unlock();
|
||||
|
||||
tr2.join();
|
||||
tr1.join();
|
||||
tw2.join();
|
||||
tw1.join();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename RW>
|
||||
void test_timed_read_write_mutex(RW &rw)
|
||||
void test_try_read_write_mutex(RW& rw, bool test_promotion_and_demotion)
|
||||
{
|
||||
data<RW> r1(1,rw,1);
|
||||
data<RW> r2(2,rw,3);
|
||||
data<RW> w1(3,rw,3);
|
||||
data<RW> w2(4,rw,1);
|
||||
//Repeat the plain tests with the try lock.
|
||||
//This is important to verify that try locks are proper
|
||||
//read_write_mutexes as well.
|
||||
|
||||
// We begin with some specialized tests for "timed" behavior
|
||||
test_plain_read_write_mutex(rw, test_promotion_and_demotion);
|
||||
|
||||
shared_val = 0;
|
||||
//Verify try_* operations with write-locked mutex
|
||||
{
|
||||
typename RW::scoped_try_read_write_lock l(rw, boost::read_write_lock_state::write_locked);
|
||||
|
||||
// Writer one will hold the lock for 3 seconds.
|
||||
boost::thread tw1(thread_adapter<RW>(timed_writer,&w1,rw));
|
||||
shared_test_writelocked = true;
|
||||
shared_test_readlocked = false;
|
||||
shared_test_unlocked = false;
|
||||
|
||||
boost::thread test_thread(thread_adapter<RW>(run_try_tests, NULL, rw));
|
||||
test_thread.join();
|
||||
}
|
||||
|
||||
boost::thread::sleep(xsecs(1));
|
||||
// Writer two will "clearly" try for the lock after the readers
|
||||
// have tried for it. Writer will wait up 1 second for the lock.
|
||||
// This write will fail.
|
||||
boost::thread tw2(thread_adapter<RW>(timed_writer,&w2,rw));
|
||||
//Verify try_* operations with read-locked mutex
|
||||
{
|
||||
typename RW::scoped_try_read_write_lock l(rw, boost::read_write_lock_state::read_locked);
|
||||
|
||||
shared_test_writelocked = false;
|
||||
shared_test_readlocked = true;
|
||||
shared_test_unlocked = false;
|
||||
|
||||
boost::thread test_thread(thread_adapter<RW>(run_try_tests, NULL, rw));
|
||||
test_thread.join();
|
||||
}
|
||||
|
||||
// Readers one and two will "clearly" try for the lock after writer
|
||||
// one already holds it. 1st reader will wait 1 second, and will fail
|
||||
// to get the lock. 2nd reader will wait 3 seconds, and will get
|
||||
// the lock.
|
||||
//Verify try_* operations with unlocked mutex
|
||||
{
|
||||
shared_test_writelocked = false;
|
||||
shared_test_readlocked = false;
|
||||
shared_test_unlocked = true;
|
||||
|
||||
boost::thread test_thread(thread_adapter<RW>(run_try_tests, NULL, rw));
|
||||
test_thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
boost::thread tr1(thread_adapter<RW>(timed_reader,&r1,rw));
|
||||
boost::thread tr2(thread_adapter<RW>(timed_reader,&r2,rw));
|
||||
template<typename RW>
|
||||
void test_timed_read_write_mutex(RW& rw, bool test_promotion_and_demotion)
|
||||
{
|
||||
//Repeat the try tests with the timed lock.
|
||||
//This is important to verify that timed locks are proper
|
||||
//try locks as well.
|
||||
|
||||
test_try_read_write_mutex(rw, test_promotion_and_demotion);
|
||||
|
||||
tw1.join();
|
||||
tr1.join();
|
||||
tr2.join();
|
||||
tw2.join();
|
||||
|
||||
|
||||
BOOST_TEST(w1.m_value == 10);
|
||||
BOOST_TEST(r1.m_value == -1);
|
||||
BOOST_TEST(r2.m_value == 10);
|
||||
BOOST_TEST(w2.m_value == -1);
|
||||
|
||||
// We follow by repeating the try tests with the timed lock.
|
||||
// This is important to verify that timed locks are proper try locks as
|
||||
// well
|
||||
test_try_read_write_mutex(rw);
|
||||
//:More tests here
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void test_read_write_mutex()
|
||||
void do_test_read_write_mutex(bool test_promotion_and_demotion)
|
||||
{
|
||||
int i;
|
||||
for(i = (int) boost::read_write_scheduling_policy::writer_priority;
|
||||
//Run every test for each scheduling policy
|
||||
|
||||
for(int i = (int) boost::read_write_scheduling_policy::writer_priority;
|
||||
i <= (int) boost::read_write_scheduling_policy::alternating_single_read;
|
||||
i++)
|
||||
{
|
||||
boost::read_write_mutex plain_rw(static_cast<boost::read_write_scheduling_policy::read_write_scheduling_policy_enum>(i));
|
||||
boost::try_read_write_mutex try_rw(static_cast<boost::read_write_scheduling_policy::read_write_scheduling_policy_enum>(i));
|
||||
boost::timed_read_write_mutex timed_rw(static_cast<boost::read_write_scheduling_policy::read_write_scheduling_policy_enum>(i));
|
||||
std::cout << "plain test, sp=" << i
|
||||
<< (test_promotion_and_demotion ? " with promotion & demotion" : " without promotion & demotion")
|
||||
<< "\n";
|
||||
std::cout.flush();
|
||||
|
||||
std::cout << "plain test, sp=" << i << "\n";
|
||||
test_plain_read_write_mutex(plain_rw);
|
||||
{
|
||||
boost::read_write_mutex plain_rw(static_cast<boost::read_write_scheduling_policy::read_write_scheduling_policy_enum>(i));
|
||||
test_plain_read_write_mutex(plain_rw, test_promotion_and_demotion);
|
||||
}
|
||||
|
||||
std::cout << "try test, sp=" << i << "\n";
|
||||
test_try_read_write_mutex(try_rw);
|
||||
std::cout << "try test, sp=" << i
|
||||
<< (test_promotion_and_demotion ? " with promotion & demotion" : " without promotion & demotion")
|
||||
<< "\n";
|
||||
std::cout.flush();
|
||||
|
||||
std::cout << "timed test, sp=" << i << "\n";
|
||||
test_timed_read_write_mutex(timed_rw);
|
||||
{
|
||||
boost::try_read_write_mutex try_rw(static_cast<boost::read_write_scheduling_policy::read_write_scheduling_policy_enum>(i));
|
||||
test_try_read_write_mutex(try_rw, test_promotion_and_demotion);
|
||||
}
|
||||
|
||||
std::cout << "timed test, sp=" << i
|
||||
<< (test_promotion_and_demotion ? " with promotion & demotion" : " without promotion & demotion")
|
||||
<< "\n";
|
||||
std::cout.flush();
|
||||
|
||||
{
|
||||
boost::timed_read_write_mutex timed_rw(static_cast<boost::read_write_scheduling_policy::read_write_scheduling_policy_enum>(i));
|
||||
test_timed_read_write_mutex(timed_rw, test_promotion_and_demotion);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test_read_write_mutex()
|
||||
{
|
||||
do_test_read_write_mutex(false);
|
||||
do_test_read_write_mutex(true);
|
||||
}
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
|
||||
@@ -29,9 +29,9 @@ void simple_thread()
|
||||
void comparison_thread(boost::thread* parent)
|
||||
{
|
||||
boost::thread thrd;
|
||||
BOOST_TEST(thrd != *parent);
|
||||
BOOST_CHECK(thrd != *parent);
|
||||
boost::thread thrd2;
|
||||
BOOST_TEST(thrd == thrd2);
|
||||
BOOST_CHECK(thrd == thrd2);
|
||||
}
|
||||
|
||||
void test_sleep()
|
||||
@@ -41,7 +41,7 @@ void test_sleep()
|
||||
|
||||
// Ensure it's in a range instead of checking actual equality due to time
|
||||
// lapse
|
||||
BOOST_CHECK(in_range(xt));
|
||||
BOOST_CHECK(in_range(xt, 2));
|
||||
}
|
||||
|
||||
void do_test_creation()
|
||||
|
||||
@@ -30,8 +30,8 @@ inline boost::xtime delay(int secs, int msecs=0, int nsecs=0)
|
||||
const int NANOSECONDS_PER_MILLISECOND = 1000000;
|
||||
|
||||
boost::xtime xt;
|
||||
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC),
|
||||
static_cast<int>(boost::TIME_UTC));
|
||||
if (boost::TIME_UTC != boost::xtime_get (&xt, boost::TIME_UTC))
|
||||
BOOST_ERROR ("boost::xtime_get != boost::TIME_UTC");
|
||||
|
||||
nsecs += xt.nsec;
|
||||
msecs += nsecs / NANOSECONDS_PER_MILLISECOND;
|
||||
@@ -140,10 +140,10 @@ void timed_test(F func, int secs,
|
||||
}
|
||||
|
||||
template <typename F, typename T>
|
||||
class binder
|
||||
class thread_binder
|
||||
{
|
||||
public:
|
||||
binder(const F& func, const T& param)
|
||||
thread_binder(const F& func, const T& param)
|
||||
: func(func), param(param) { }
|
||||
void operator()() const { func(param); }
|
||||
|
||||
@@ -153,9 +153,9 @@ private:
|
||||
};
|
||||
|
||||
template <typename F, typename T>
|
||||
binder<F, T> bind(const F& func, const T& param)
|
||||
thread_binder<F, T> bind(const F& func, const T& param)
|
||||
{
|
||||
return binder<F, T>(func, param);
|
||||
return thread_binder<F, T>(func, param);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
|
||||
Reference in New Issue
Block a user