2
0
mirror of https://github.com/boostorg/thread.git synced 2026-02-07 23:02:13 +00:00

Compare commits

..

3 Commits

Author SHA1 Message Date
Hartmut Kaiser
03ef4775b9 Removed part of the Boost files from the SPIRIT_MINIBOOST branch.
[SVN r26368]
2004-11-30 07:52:25 +00:00
Hartmut Kaiser
1f16717aa0 Removed part of the Boost files from the SPIRIT_MINIBOOST branch.
[SVN r26362]
2004-11-29 21:25:31 +00:00
nobody
1a0c11f4cd This commit was manufactured by cvs2svn to create branch
'SPIRIT_MINIBOOST'.

[SVN r26343]
2004-11-29 07:29:20 +00:00
31 changed files with 565 additions and 4493 deletions

View File

@@ -46,6 +46,7 @@ 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:
@@ -101,8 +102,7 @@ import ./threads ;
<template>boost_thread_lib_base
: ## requirements ##
<define>BOOST_THREAD_LIB_NAME=$(boost_thread_lib_name_ptw32)
$(boost_thread_lib_settings_ptw32)
: ## default build ##
$(pthreads-win32)
;
dll $(boost_thread_lib_name_ptw32)
@@ -110,8 +110,7 @@ import ./threads ;
<template>boost_thread_dll_base
: ## requirements ##
<define>BOOST_THREAD_LIB_NAME=$(boost_thread_lib_name_ptw32)
$(boost_thread_lib_settings_ptw32)
: ## default build ##
$(pthreads-win32)
;
stage bin-stage

View File

@@ -54,7 +54,7 @@ last-revision="$Date$">
<title>ACM Computing Surveys</title>
<volumenum>Vol. 5</volumenum>
<issuenum>No. 4</issuenum>
<date>December, 1973</date>
<date>December, 1983</date>
</biblioset>
<biblioset relation="article">
<author>0-201-63392-2

View File

@@ -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"/>

View File

@@ -1,24 +0,0 @@
// Copyright (C) 2001-2003
// 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.
#if !defined(BOOST_THREAD_WEK01082003_HPP)
#define BOOST_THREAD_WEK01082003_HPP
#include <boost/thread/thread.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/exceptions.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/once.hpp>
#include <boost/thread/recursive_mutex.hpp>
#include <boost/thread/tss.hpp>
#include <boost/thread/xtime.hpp>
#endif

View File

@@ -1,40 +0,0 @@
// 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.
#ifndef BOOST_BARRIER_JDM030602_HPP
#define BOOST_BARRIER_JDM030602_HPP
#include <boost/thread/detail/config.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>
namespace boost {
class BOOST_THREAD_DECL barrier
{
public:
barrier(unsigned int count);
~barrier();
bool wait();
private:
mutex m_mutex;
condition m_cond;
unsigned int m_threshold;
unsigned int m_count;
unsigned int m_generation;
};
} // namespace boost
#endif

View File

@@ -1,198 +0,0 @@
// Copyright (C) 2001-2003
// 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.
#ifndef BOOST_CONDITION_WEK070601_HPP
#define BOOST_CONDITION_WEK070601_HPP
#include <boost/thread/detail/config.hpp>
#include <boost/thread/exceptions.hpp>
#include <boost/utility.hpp>
#include <boost/thread/detail/lock.hpp>
#if defined(BOOST_HAS_PTHREADS)
# include <pthread.h>
#elif defined(BOOST_HAS_MPTASKS)
# include "scoped_critical_region.hpp"
#endif
namespace boost {
struct xtime;
namespace detail {
class BOOST_THREAD_DECL condition_impl : private noncopyable
{
friend class condition;
public:
condition_impl();
~condition_impl();
void notify_one();
void notify_all();
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
void enter_wait();
void do_wait();
bool do_timed_wait(const xtime& xt);
#elif defined(BOOST_HAS_PTHREADS)
void do_wait(pthread_mutex_t* pmutex);
bool do_timed_wait(const xtime& xt, pthread_mutex_t* pmutex);
#endif
#if defined(BOOST_HAS_WINTHREADS)
void* m_gate;
void* m_queue;
void* m_mutex;
unsigned m_gone; // # threads that timed out and never made it to m_queue
unsigned long m_blocked; // # threads blocked on the condition
unsigned m_waiting; // # threads no longer waiting for the condition but
// still waiting to be removed from m_queue
#elif defined(BOOST_HAS_PTHREADS)
pthread_cond_t m_condition;
#elif defined(BOOST_HAS_MPTASKS)
MPSemaphoreID m_gate;
MPSemaphoreID m_queue;
threads::mac::detail::scoped_critical_region m_mutex;
threads::mac::detail::scoped_critical_region m_mutex_mutex;
unsigned m_gone; // # threads that timed out and never made it to m_queue
unsigned long m_blocked; // # threads blocked on the condition
unsigned m_waiting; // # threads no longer waiting for the condition but
// still waiting to be removed from m_queue
#endif
};
} // namespace detail
class condition : private noncopyable
{
public:
condition() { }
~condition() { }
void notify_one() { m_impl.notify_one(); }
void notify_all() { m_impl.notify_all(); }
template <typename L>
void wait(L& lock)
{
if (!lock)
throw lock_error();
do_wait(lock.m_mutex);
}
template <typename L, typename Pr>
void wait(L& lock, Pr pred)
{
if (!lock)
throw lock_error();
while (!pred())
do_wait(lock.m_mutex);
}
template <typename L>
bool timed_wait(L& lock, const xtime& xt)
{
if (!lock)
throw lock_error();
return do_timed_wait(lock.m_mutex, xt);
}
template <typename L, typename Pr>
bool timed_wait(L& lock, const xtime& xt, Pr pred)
{
if (!lock)
throw lock_error();
while (!pred())
{
if (!do_timed_wait(lock.m_mutex, xt))
return false;
}
return true;
}
private:
detail::condition_impl m_impl;
template <typename M>
void do_wait(M& mutex)
{
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
m_impl.enter_wait();
#endif
typedef detail::thread::lock_ops<M>
#if defined(__HP_aCC) && __HP_aCC <= 33900 && !defined(BOOST_STRICT_CONFIG)
# define lock_ops lock_ops_ // HP confuses lock_ops witht the template
#endif
lock_ops;
typename lock_ops::lock_state state;
lock_ops::unlock(mutex, state);
#if defined(BOOST_HAS_PTHREADS)
m_impl.do_wait(state.pmutex);
#elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
m_impl.do_wait();
#endif
lock_ops::lock(mutex, state);
#undef lock_ops
}
template <typename M>
bool do_timed_wait(M& mutex, const xtime& xt)
{
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
m_impl.enter_wait();
#endif
typedef detail::thread::lock_ops<M>
#if defined(__HP_aCC) && __HP_aCC <= 33900 && !defined(BOOST_STRICT_CONFIG)
# define lock_ops lock_ops_ // HP confuses lock_ops witht the template
#endif
lock_ops;
typename lock_ops::lock_state state;
lock_ops::unlock(mutex, state);
bool ret = false;
#if defined(BOOST_HAS_PTHREADS)
ret = m_impl.do_timed_wait(xt, state.pmutex);
#elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
ret = m_impl.do_timed_wait(xt);
#endif
lock_ops::lock(mutex, state);
#undef lock_ops
return ret;
}
};
} // namespace boost
// Change Log:
// 8 Feb 01 WEKEMPF Initial version.
// 22 May 01 WEKEMPF Modified to use xtime for time outs.
// 23 May 01 WEKEMPF Removed "duration" timed_waits, as they are too
// difficult to use with spurious wakeups.
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
#endif // BOOST_CONDITION_WEK070601_HPP

View File

@@ -1,86 +0,0 @@
// Copyright (C) 2001-2003
// 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.
#ifndef BOOST_THREAD_CONFIG_WEK01032003_HPP
#define BOOST_THREAD_CONFIG_WEK01032003_HPP
#include <boost/config.hpp>
// insist on threading support being available:
#include <boost/config/requires_threads.hpp>
#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 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
# 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
#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:
//
#if defined(BOOST_THREAD_LIB_NAME)
# define BOOST_LIB_NAME BOOST_THREAD_LIB_NAME
#else
# define BOOST_LIB_NAME boost_thread
#endif
//
// If we're importing code from a dll, then tell auto_link.hpp about it:
//
// And include the header that does the work:
//
#include <boost/config/auto_link.hpp>
#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.

View File

@@ -1,39 +0,0 @@
// Copyright (C) 2001-2003
// Mac Murrett
//
// 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)
//
// See http://www.boost.org for most recent version including documentation.
#ifndef BOOST_FORCE_CAST_MJM012402_HPP
#define BOOST_FORCE_CAST_MJM012402_HPP
#include <boost/thread/detail/config.hpp>
namespace boost {
namespace detail {
namespace thread {
// force_cast will convert anything to anything.
// general case
template<class Return_Type, class Argument_Type>
inline Return_Type &force_cast(Argument_Type &rSrc)
{
return(*reinterpret_cast<Return_Type *>(&rSrc));
}
// specialization for const
template<class Return_Type, class Argument_Type>
inline const Return_Type &force_cast(const Argument_Type &rSrc)
{
return(*reinterpret_cast<const Return_Type *>(&rSrc));
}
} // namespace thread
} // namespace detail
} // namespace boost
#endif // BOOST_FORCE_CAST_MJM012402_HPP

View File

@@ -1,214 +0,0 @@
// Copyright (C) 2001-2003
// 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.
#ifndef BOOST_XLOCK_WEK070601_HPP
#define BOOST_XLOCK_WEK070601_HPP
#include <boost/thread/detail/config.hpp>
#include <boost/utility.hpp>
#include <boost/thread/exceptions.hpp>
namespace boost {
class condition;
struct xtime;
namespace detail { namespace thread {
template <typename Mutex>
class lock_ops : private noncopyable
{
private:
lock_ops() { }
public:
typedef typename Mutex::cv_state lock_state;
static void lock(Mutex& m)
{
m.do_lock();
}
static bool trylock(Mutex& m)
{
return m.do_trylock();
}
static bool timedlock(Mutex& m, const xtime& xt)
{
return m.do_timedlock(xt);
}
static void unlock(Mutex& m)
{
m.do_unlock();
}
static void lock(Mutex& m, lock_state& state)
{
m.do_lock(state);
}
static void unlock(Mutex& m, lock_state& state)
{
m.do_unlock(state);
}
};
template <typename Mutex>
class scoped_lock : private noncopyable
{
public:
typedef Mutex mutex_type;
explicit scoped_lock(Mutex& mx, bool initially_locked=true)
: m_mutex(mx), m_locked(false)
{
if (initially_locked) lock();
}
~scoped_lock()
{
if (m_locked) unlock();
}
void lock()
{
if (m_locked) throw lock_error();
lock_ops<Mutex>::lock(m_mutex);
m_locked = true;
}
void unlock()
{
if (!m_locked) throw lock_error();
lock_ops<Mutex>::unlock(m_mutex);
m_locked = false;
}
bool locked() const { return m_locked; }
operator const void*() const { return m_locked ? this : 0; }
private:
friend class boost::condition;
Mutex& m_mutex;
bool m_locked;
};
template <typename TryMutex>
class scoped_try_lock : private noncopyable
{
public:
typedef TryMutex mutex_type;
explicit scoped_try_lock(TryMutex& mx)
: m_mutex(mx), m_locked(false)
{
try_lock();
}
scoped_try_lock(TryMutex& mx, bool initially_locked)
: m_mutex(mx), m_locked(false)
{
if (initially_locked) lock();
}
~scoped_try_lock()
{
if (m_locked) unlock();
}
void lock()
{
if (m_locked) throw lock_error();
lock_ops<TryMutex>::lock(m_mutex);
m_locked = true;
}
bool try_lock()
{
if (m_locked) throw lock_error();
return (m_locked = lock_ops<TryMutex>::trylock(m_mutex));
}
void unlock()
{
if (!m_locked) throw lock_error();
lock_ops<TryMutex>::unlock(m_mutex);
m_locked = false;
}
bool locked() const { return m_locked; }
operator const void*() const { return m_locked ? this : 0; }
private:
friend class boost::condition;
TryMutex& m_mutex;
bool m_locked;
};
template <typename TimedMutex>
class scoped_timed_lock : private noncopyable
{
public:
typedef TimedMutex mutex_type;
scoped_timed_lock(TimedMutex& mx, const xtime& xt)
: m_mutex(mx), m_locked(false)
{
timed_lock(xt);
}
scoped_timed_lock(TimedMutex& mx, bool initially_locked)
: m_mutex(mx), m_locked(false)
{
if (initially_locked) lock();
}
~scoped_timed_lock()
{
if (m_locked) unlock();
}
void lock()
{
if (m_locked) throw lock_error();
lock_ops<TimedMutex>::lock(m_mutex);
m_locked = true;
}
bool try_lock()
{
if (m_locked) throw lock_error();
return (m_locked = lock_ops<TimedMutex>::trylock(m_mutex));
}
bool timed_lock(const xtime& xt)
{
if (m_locked) throw lock_error();
return (m_locked = lock_ops<TimedMutex>::timedlock(m_mutex, xt));
}
void unlock()
{
if (!m_locked) throw lock_error();
lock_ops<TimedMutex>::unlock(m_mutex);
m_locked = false;
}
bool locked() const { return m_locked; }
operator const void*() const { return m_locked ? this : 0; }
private:
friend class boost::condition;
TimedMutex& m_mutex;
bool m_locked;
};
} // namespace thread
} // namespace detail
} // namespace boost
#endif // BOOST_XLOCK_WEK070601_HPP
// Change Log:
// 8 Feb 01 WEKEMPF Initial version.
// 22 May 01 WEKEMPF Modified to use xtime for time outs.
// 30 Jul 01 WEKEMPF Moved lock types into boost::detail::thread. Renamed
// some types. Added locked() methods.

File diff suppressed because it is too large Load Diff

View File

@@ -1,59 +0,0 @@
// Copyright (C) 2001-2003
// Mac Murrett
//
// 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)
//
// See http://www.boost.org for most recent version including documentation.
#ifndef BOOST_SINGLETON_MJM012402_HPP
#define BOOST_SINGLETON_MJM012402_HPP
#include <boost/thread/detail/config.hpp>
namespace boost {
namespace detail {
namespace thread {
// class singleton has the same goal as all singletons: create one instance of
// a class on demand, then dish it out as requested.
template <class T>
class singleton : private T
{
private:
singleton();
~singleton();
public:
static T &instance();
};
template <class T>
inline singleton<T>::singleton()
{
/* no-op */
}
template <class T>
inline singleton<T>::~singleton()
{
/* no-op */
}
template <class T>
/*static*/ T &singleton<T>::instance()
{
// function-local static to force this to work correctly at static
// initialization time.
static singleton<T> s_oT;
return(s_oT);
}
} // namespace thread
} // namespace detail
} // namespace boost
#endif // BOOST_SINGLETON_MJM012402_HPP

View File

@@ -1,78 +0,0 @@
// (C) Copyright Michael Glassford 2004.
// Use, modification and distribution are subject to 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)
#if !defined(BOOST_TLS_HOOKS_HPP)
#define BOOST_TLS_HOOKS_HPP
#include <boost/thread/detail/config.hpp>
#if defined(BOOST_HAS_WINTHREADS)
typedef void (__cdecl *thread_exit_handler)(void);
extern "C" BOOST_THREAD_DECL int at_thread_exit(
thread_exit_handler exit_handler
);
//Add a function to the list of functions that will
//be called when a thread is about to exit.
//Currently only implemented for Win32, but should
//later be implemented for all platforms.
//Used by Win32 implementation of Boost.Threads
//tss to peform cleanup.
//Like the C runtime library atexit() function,
//which it mimics, at_thread_exit() returns
//zero if successful and a nonzero
//value if an error occurs.
#endif //defined(BOOST_HAS_WINTHREADS)
#if defined(BOOST_HAS_WINTHREADS)
extern "C" BOOST_THREAD_DECL void on_process_enter(void);
//Function to be called when the exe or dll
//that uses Boost.Threads first starts
//or is first loaded.
//Should be called only before the first call to
//on_thread_enter().
//Called automatically by Boost.Threads when
//a method for doing so has been discovered.
//May be omitted; may be called multiple times.
extern "C" BOOST_THREAD_DECL void on_process_exit(void);
//Function to be called when the exe or dll
//that uses Boost.Threads first starts
//or is first loaded.
//Should be called only after the last call to
//on_exit_thread().
//Called automatically by Boost.Threads when
//a method for doing so has been discovered.
//Must not be omitted; may be called multiple times.
extern "C" BOOST_THREAD_DECL void on_thread_enter(void);
//Function to be called just after a thread starts
//in an exe or dll that uses Boost.Threads.
//Must be called in the context of the thread
//that is starting.
//Called automatically by Boost.Threads when
//a method for doing so has been discovered.
//May be omitted; may be called multiple times.
extern "C" BOOST_THREAD_DECL void on_thread_exit(void);
//Function to be called just be fore a thread ends
//in an exe or dll that uses Boost.Threads.
//Must be called in the context of the thread
//that is ending.
//Called automatically by Boost.Threads when
//a method for doing so has been discovered.
//Must not be omitted; may be called multiple times.
extern "C" void tss_cleanup_implemented(void);
//Dummy function used both to detect whether tss cleanup
//cleanup has been implemented and to force
//it to be linked into the Boost.Threads library.
#endif //defined(BOOST_HAS_WINTHREADS)
#endif //!defined(BOOST_TLS_HOOKS_HPP)

View File

@@ -1,101 +0,0 @@
// Copyright (C) 2001-2003
// 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.
#ifndef BOOST_THREAD_EXCEPTIONS_PDM070801_H
#define BOOST_THREAD_EXCEPTIONS_PDM070801_H
#include <boost/thread/detail/config.hpp>
// pdm: Sorry, but this class is used all over the place & I end up
// with recursive headers if I don't separate it
// wek: Not sure why recursive headers would cause compilation problems
// given the include guards, but regardless it makes sense to
// seperate this out any way.
#include <string>
#include <stdexcept>
namespace boost {
class BOOST_THREAD_DECL thread_exception : public std::exception
{
protected:
thread_exception();
thread_exception(int sys_err_code);
public:
~thread_exception() throw();
int native_error() const;
const char* message() const;
private:
int m_sys_err;
};
class BOOST_THREAD_DECL lock_error : public thread_exception
{
public:
lock_error();
lock_error(int sys_err_code);
~lock_error() throw();
virtual const char* what() const throw();
};
class BOOST_THREAD_DECL thread_resource_error : public thread_exception
{
public:
thread_resource_error();
thread_resource_error(int sys_err_code);
~thread_resource_error() throw();
virtual const char* what() const throw();
};
class BOOST_THREAD_DECL unsupported_thread_option : public thread_exception
{
public:
unsupported_thread_option();
unsupported_thread_option(int sys_err_code);
~unsupported_thread_option() throw();
virtual const char* what() const throw();
};
class BOOST_THREAD_DECL invalid_thread_argument : public thread_exception
{
public:
invalid_thread_argument();
invalid_thread_argument(int sys_err_code);
~invalid_thread_argument() throw();
virtual const char* what() const throw();
};
class BOOST_THREAD_DECL thread_permission_error : public thread_exception
{
public:
thread_permission_error();
thread_permission_error(int sys_err_code);
~thread_permission_error() throw();
virtual const char* what() const throw();
};
} // namespace boost
#endif // BOOST_THREAD_CONFIG_PDM070801_H
// Change log:
// 3 Jan 03 WEKEMPF Modified for DLL implementation.

View File

@@ -1,167 +0,0 @@
// Copyright (C) 2001-2003
// 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.
#ifndef BOOST_MUTEX_WEK070601_HPP
#define BOOST_MUTEX_WEK070601_HPP
#include <boost/thread/detail/config.hpp>
#include <boost/utility.hpp>
#include <boost/thread/detail/lock.hpp>
#if defined(BOOST_HAS_PTHREADS)
# include <pthread.h>
#endif
#if defined(BOOST_HAS_MPTASKS)
# include "scoped_critical_region.hpp"
#endif
namespace boost {
struct xtime;
class BOOST_THREAD_DECL mutex
: private noncopyable
{
public:
friend class detail::thread::lock_ops<mutex>;
typedef detail::thread::scoped_lock<mutex> scoped_lock;
mutex();
~mutex();
private:
#if defined(BOOST_HAS_WINTHREADS)
typedef void* cv_state;
#elif defined(BOOST_HAS_PTHREADS)
struct cv_state
{
pthread_mutex_t* pmutex;
};
#elif defined(BOOST_HAS_MPTASKS)
struct cv_state
{
};
#endif
void do_lock();
void do_unlock();
void do_lock(cv_state& state);
void do_unlock(cv_state& state);
#if defined(BOOST_HAS_WINTHREADS)
void* m_mutex;
bool m_critical_section;
#elif defined(BOOST_HAS_PTHREADS)
pthread_mutex_t m_mutex;
#elif defined(BOOST_HAS_MPTASKS)
threads::mac::detail::scoped_critical_region m_mutex;
threads::mac::detail::scoped_critical_region m_mutex_mutex;
#endif
};
class BOOST_THREAD_DECL try_mutex
: private noncopyable
{
public:
friend class detail::thread::lock_ops<try_mutex>;
typedef detail::thread::scoped_lock<try_mutex> scoped_lock;
typedef detail::thread::scoped_try_lock<try_mutex> scoped_try_lock;
try_mutex();
~try_mutex();
private:
#if defined(BOOST_HAS_WINTHREADS)
typedef void* cv_state;
#elif defined(BOOST_HAS_PTHREADS)
struct cv_state
{
pthread_mutex_t* pmutex;
};
#elif defined(BOOST_HAS_MPTASKS)
struct cv_state
{
};
#endif
void do_lock();
bool do_trylock();
void do_unlock();
void do_lock(cv_state& state);
void do_unlock(cv_state& state);
#if defined(BOOST_HAS_WINTHREADS)
void* m_mutex;
bool m_critical_section;
#elif defined(BOOST_HAS_PTHREADS)
pthread_mutex_t m_mutex;
#elif defined(BOOST_HAS_MPTASKS)
threads::mac::detail::scoped_critical_region m_mutex;
threads::mac::detail::scoped_critical_region m_mutex_mutex;
#endif
};
class BOOST_THREAD_DECL timed_mutex
: private noncopyable
{
public:
friend class detail::thread::lock_ops<timed_mutex>;
typedef detail::thread::scoped_lock<timed_mutex> scoped_lock;
typedef detail::thread::scoped_try_lock<timed_mutex> scoped_try_lock;
typedef detail::thread::scoped_timed_lock<timed_mutex> scoped_timed_lock;
timed_mutex();
~timed_mutex();
private:
#if defined(BOOST_HAS_WINTHREADS)
typedef void* cv_state;
#elif defined(BOOST_HAS_PTHREADS)
struct cv_state
{
pthread_mutex_t* pmutex;
};
#elif defined(BOOST_HAS_MPTASKS)
struct cv_state
{
};
#endif
void do_lock();
bool do_trylock();
bool do_timedlock(const xtime& xt);
void do_unlock();
void do_lock(cv_state& state);
void do_unlock(cv_state& state);
#if defined(BOOST_HAS_WINTHREADS)
void* m_mutex;
#elif defined(BOOST_HAS_PTHREADS)
pthread_mutex_t m_mutex;
pthread_cond_t m_condition;
bool m_locked;
#elif defined(BOOST_HAS_MPTASKS)
threads::mac::detail::scoped_critical_region m_mutex;
threads::mac::detail::scoped_critical_region m_mutex_mutex;
#endif
};
} // namespace boost
// Change Log:
// 8 Feb 01 WEKEMPF Initial version.
// 22 May 01 WEKEMPF Modified to use xtime for time outs. Factored out
// to three classes, mutex, try_mutex and timed_mutex.
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
#endif // BOOST_MUTEX_WEK070601_HPP

View File

@@ -1,42 +0,0 @@
// Copyright (C) 2001-2003
// 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.
#ifndef BOOST_ONCE_WEK080101_HPP
#define BOOST_ONCE_WEK080101_HPP
#include <boost/thread/detail/config.hpp>
#if defined(BOOST_HAS_PTHREADS)
# include <pthread.h>
#endif
namespace boost {
#if defined(BOOST_HAS_PTHREADS)
typedef pthread_once_t once_flag;
#define BOOST_ONCE_INIT PTHREAD_ONCE_INIT
#elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
typedef long once_flag;
#define BOOST_ONCE_INIT 0
#endif
void BOOST_THREAD_DECL call_once(void (*func)(), once_flag& flag);
} // namespace boost
// Change Log:
// 1 Aug 01 WEKEMPF Initial version.
#endif // BOOST_ONCE_WEK080101_HPP

View File

@@ -1,283 +0,0 @@
// Copyright (C) 2002-2003
// 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,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. David Moore makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
// A Boost::threads implementation of a synchronization
// primitive which can allow multiple readers or a single
// writer to have access to a shared resource.
#ifndef BOOST_READ_WRITE_MUTEX_JDM030602_HPP
#define BOOST_READ_WRITE_MUTEX_JDM030602_HPP
#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>
#include <boost/thread/detail/read_write_lock.hpp>
#include <boost/thread/condition.hpp>
namespace boost {
namespace read_write_scheduling_policy {
enum read_write_scheduling_policy_enum
{
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 one queued reader
};
} // namespace read_write_scheduling_policy
namespace detail {
namespace thread {
// Shared implementation construct for explicit Scheduling Policies
// This implementation is susceptible to self-deadlock, though....
template<typename Mutex>
struct read_write_mutex_impl
{
typedef Mutex mutex_type;
typedef detail::thread::scoped_lock<Mutex> scoped_lock;
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);
#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;
bool m_state_waiting_promotion;
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();
void do_write_lock();
void do_write_unlock();
void do_read_unlock();
bool do_try_write_lock();
bool do_try_read_lock();
bool do_timed_write_lock(const xtime &xt);
bool do_timed_read_lock(const xtime &xt);
void do_demote_to_read_lock();
bool do_try_demote_to_read_lock();
bool do_timed_demote_to_read_lock(const xtime &xt);
void do_promote_to_write_lock();
bool do_try_promote_to_write_lock();
bool do_timed_promote_to_write_lock(const xtime &xt);
bool locked();
read_write_lock_state::read_write_lock_state_enum state();
private:
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
} // namespace thread
class BOOST_THREAD_DECL read_write_mutex : private noncopyable
{
public:
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; }
friend class detail::thread::read_write_lock_ops<read_write_mutex>;
typedef detail::thread::scoped_read_write_lock<
read_write_mutex> scoped_read_write_lock;
typedef detail::thread::scoped_read_lock<
read_write_mutex> scoped_read_lock;
typedef detail::thread::scoped_write_lock<
read_write_mutex> scoped_write_lock;
private:
// Operations that will eventually be done only
// via lock types
void do_write_lock();
void do_read_lock();
void do_write_unlock();
void do_read_unlock();
void do_demote_to_read_lock();
void do_promote_to_write_lock();
bool locked();
read_write_lock_state::read_write_lock_state_enum state();
detail::thread::read_write_mutex_impl<mutex> m_impl;
};
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);
~try_read_write_mutex();
read_write_scheduling_policy::read_write_scheduling_policy_enum policy() const { return m_impl.m_sp; }
friend class detail::thread::read_write_lock_ops<try_read_write_mutex>;
typedef detail::thread::scoped_read_write_lock<
try_read_write_mutex> scoped_read_write_lock;
typedef detail::thread::scoped_try_read_write_lock<
try_read_write_mutex> scoped_try_read_write_lock;
typedef detail::thread::scoped_read_lock<
try_read_write_mutex> scoped_read_lock;
typedef detail::thread::scoped_try_read_lock<
try_read_write_mutex> scoped_try_read_lock;
typedef detail::thread::scoped_write_lock<
try_read_write_mutex> scoped_write_lock;
typedef detail::thread::scoped_try_write_lock<
try_read_write_mutex> scoped_try_write_lock;
private:
// Operations that will eventually be done only
// via lock types
void do_write_lock();
void do_read_lock();
void do_write_unlock();
void do_read_unlock();
bool do_try_write_lock();
bool do_try_read_lock();
void do_demote_to_read_lock();
bool do_try_demote_to_read_lock();
void do_promote_to_write_lock();
bool do_try_promote_to_write_lock();
bool locked();
read_write_lock_state::read_write_lock_state_enum state();
detail::thread::read_write_mutex_impl<try_mutex> m_impl;
};
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);
~timed_read_write_mutex();
read_write_scheduling_policy::read_write_scheduling_policy_enum policy() const { return m_impl.m_sp; }
friend class detail::thread::read_write_lock_ops<timed_read_write_mutex>;
typedef detail::thread::scoped_read_write_lock<
timed_read_write_mutex> scoped_read_write_lock;
typedef detail::thread::scoped_try_read_write_lock<
timed_read_write_mutex> scoped_try_read_write_lock;
typedef detail::thread::scoped_timed_read_write_lock<
timed_read_write_mutex> scoped_timed_read_write_lock;
typedef detail::thread::scoped_read_lock<
timed_read_write_mutex> scoped_read_lock;
typedef detail::thread::scoped_try_read_lock<
timed_read_write_mutex> scoped_try_read_lock;
typedef detail::thread::scoped_timed_read_lock<
timed_read_write_mutex> scoped_timed_read_lock;
typedef detail::thread::scoped_write_lock<
timed_read_write_mutex> scoped_write_lock;
typedef detail::thread::scoped_try_write_lock<
timed_read_write_mutex> scoped_try_write_lock;
typedef detail::thread::scoped_timed_write_lock<
timed_read_write_mutex> scoped_timed_write_lock;
private:
// Operations that will eventually be done only
// via lock types
void do_write_lock();
void do_read_lock();
void do_write_unlock();
void do_read_unlock();
bool do_try_write_lock();
bool do_try_read_lock();
bool do_timed_write_lock(const xtime &xt);
bool do_timed_read_lock(const xtime &xt);
void do_demote_to_read_lock();
bool do_try_demote_to_read_lock();
bool do_timed_demote_to_read_lock(const xtime &xt);
void do_promote_to_write_lock();
bool do_try_promote_to_write_lock();
bool do_timed_promote_to_write_lock(const xtime &xt);
bool locked();
read_write_lock_state::read_write_lock_state_enum state();
detail::thread::read_write_mutex_impl<timed_mutex> m_impl;
};
} // namespace boost
#endif
// Change Log:
// 10 Mar 02
// Original version.
// 4 May 04 GlassfordM
// Implement lock promotion and demotion.
// Add locked() and state() member functions for debugging
// (should these be made public?).
// Rename to improve consistency and eliminate abbreviations:
// Use "read" and "write" instead of "shared" and "exclusive".
// Change "rd" to "read", "wr" to "write", "rw" to "read_write".
// Add mutex_type typdef.

View File

@@ -1,182 +0,0 @@
// Copyright (C) 2001-2003
// 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.
#ifndef BOOST_RECURSIVE_MUTEX_WEK070601_HPP
#define BOOST_RECURSIVE_MUTEX_WEK070601_HPP
#include <boost/thread/detail/config.hpp>
#include <boost/utility.hpp>
#include <boost/thread/detail/lock.hpp>
#if defined(BOOST_HAS_PTHREADS)
# include <pthread.h>
#endif
#if defined(BOOST_HAS_MPTASKS)
# include "scoped_critical_region.hpp"
#endif
namespace boost {
struct xtime;
class BOOST_THREAD_DECL recursive_mutex
: private noncopyable
{
public:
friend class detail::thread::lock_ops<recursive_mutex>;
typedef detail::thread::scoped_lock<recursive_mutex> scoped_lock;
recursive_mutex();
~recursive_mutex();
private:
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
typedef std::size_t cv_state;
#elif defined(BOOST_HAS_PTHREADS)
struct cv_state
{
long count;
pthread_mutex_t* pmutex;
};
#endif
void do_lock();
void do_unlock();
void do_lock(cv_state& state);
void do_unlock(cv_state& state);
#if defined(BOOST_HAS_WINTHREADS)
void* m_mutex;
bool m_critical_section;
unsigned long m_count;
#elif defined(BOOST_HAS_PTHREADS)
pthread_mutex_t m_mutex;
unsigned m_count;
# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
pthread_cond_t m_unlocked;
pthread_t m_thread_id;
bool m_valid_id;
# endif
#elif defined(BOOST_HAS_MPTASKS)
threads::mac::detail::scoped_critical_region m_mutex;
threads::mac::detail::scoped_critical_region m_mutex_mutex;
std::size_t m_count;
#endif
};
class BOOST_THREAD_DECL recursive_try_mutex
: private noncopyable
{
public:
friend class detail::thread::lock_ops<recursive_try_mutex>;
typedef detail::thread::scoped_lock<recursive_try_mutex> scoped_lock;
typedef detail::thread::scoped_try_lock<
recursive_try_mutex> scoped_try_lock;
recursive_try_mutex();
~recursive_try_mutex();
private:
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
typedef std::size_t cv_state;
#elif defined(BOOST_HAS_PTHREADS)
struct cv_state
{
long count;
pthread_mutex_t* pmutex;
};
#endif
void do_lock();
bool do_trylock();
void do_unlock();
void do_lock(cv_state& state);
void do_unlock(cv_state& state);
#if defined(BOOST_HAS_WINTHREADS)
void* m_mutex;
bool m_critical_section;
unsigned long m_count;
#elif defined(BOOST_HAS_PTHREADS)
pthread_mutex_t m_mutex;
unsigned m_count;
# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
pthread_cond_t m_unlocked;
pthread_t m_thread_id;
bool m_valid_id;
# endif
#elif defined(BOOST_HAS_MPTASKS)
threads::mac::detail::scoped_critical_region m_mutex;
threads::mac::detail::scoped_critical_region m_mutex_mutex;
std::size_t m_count;
#endif
};
class BOOST_THREAD_DECL recursive_timed_mutex
: private noncopyable
{
public:
friend class detail::thread::lock_ops<recursive_timed_mutex>;
typedef detail::thread::scoped_lock<recursive_timed_mutex> scoped_lock;
typedef detail::thread::scoped_try_lock<
recursive_timed_mutex> scoped_try_lock;
typedef detail::thread::scoped_timed_lock<
recursive_timed_mutex> scoped_timed_lock;
recursive_timed_mutex();
~recursive_timed_mutex();
private:
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
typedef std::size_t cv_state;
#elif defined(BOOST_HAS_PTHREADS)
struct cv_state
{
long count;
pthread_mutex_t* pmutex;
};
#endif
void do_lock();
bool do_trylock();
bool do_timedlock(const xtime& xt);
void do_unlock();
void do_lock(cv_state& state);
void do_unlock(cv_state& state);
#if defined(BOOST_HAS_WINTHREADS)
void* m_mutex;
unsigned long m_count;
#elif defined(BOOST_HAS_PTHREADS)
pthread_mutex_t m_mutex;
pthread_cond_t m_unlocked;
pthread_t m_thread_id;
bool m_valid_id;
unsigned m_count;
#elif defined(BOOST_HAS_MPTASKS)
threads::mac::detail::scoped_critical_region m_mutex;
threads::mac::detail::scoped_critical_region m_mutex_mutex;
std::size_t m_count;
#endif
};
} // namespace boost
#endif // BOOST_RECURSIVE_MUTEX_WEK070601_HPP
// Change Log:
// 8 Feb 01 WEKEMPF Initial version.
// 1 Jun 01 WEKEMPF Modified to use xtime for time outs. Factored out
// to three classes, mutex, try_mutex and timed_mutex.
// 11 Jun 01 WEKEMPF Modified to use PTHREAD_MUTEX_RECURSIVE if available.
// 3 Jan 03 WEKEMPF Modified for DLL implementation.

View File

@@ -1,87 +0,0 @@
// Copyright (C) 2001-2003
// 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.
#ifndef BOOST_THREAD_WEK070601_HPP
#define BOOST_THREAD_WEK070601_HPP
#include <boost/thread/detail/config.hpp>
#include <boost/utility.hpp>
#include <boost/function.hpp>
#include <boost/thread/mutex.hpp>
#include <list>
#include <memory>
#if defined(BOOST_HAS_PTHREADS)
# include <pthread.h>
# include <boost/thread/condition.hpp>
#elif defined(BOOST_HAS_MPTASKS)
# include <Multiprocessing.h>
#endif
namespace boost {
struct xtime;
class BOOST_THREAD_DECL thread : private noncopyable
{
public:
thread();
explicit thread(const function0<void>& threadfunc);
~thread();
bool operator==(const thread& other) const;
bool operator!=(const thread& other) const;
void join();
static void sleep(const xtime& xt);
static void yield();
private:
#if defined(BOOST_HAS_WINTHREADS)
void* m_thread;
unsigned int m_id;
#elif defined(BOOST_HAS_PTHREADS)
private:
pthread_t m_thread;
#elif defined(BOOST_HAS_MPTASKS)
MPQueueID m_pJoinQueueID;
MPTaskID m_pTaskID;
#endif
bool m_joinable;
};
class BOOST_THREAD_DECL thread_group : private noncopyable
{
public:
thread_group();
~thread_group();
thread* create_thread(const function0<void>& threadfunc);
void add_thread(thread* thrd);
void remove_thread(thread* thrd);
void join_all();
int size();
private:
std::list<thread*> m_threads;
mutex m_mutex;
};
} // namespace boost
// Change Log:
// 8 Feb 01 WEKEMPF Initial version.
// 1 Jun 01 WEKEMPF Added boost::thread initial implementation.
// 3 Jul 01 WEKEMPF Redesigned boost::thread to be noncopyable.
#endif // BOOST_THREAD_WEK070601_HPP

View File

@@ -1,121 +0,0 @@
// Copyright (C) 2001-2003
// 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.
#ifndef BOOST_TSS_WEK070601_HPP
#define BOOST_TSS_WEK070601_HPP
#include <boost/thread/detail/config.hpp>
#include <boost/utility.hpp>
#include <boost/function.hpp>
#include <boost/thread/exceptions.hpp>
#if defined(BOOST_HAS_PTHREADS)
# include <pthread.h>
#elif defined(BOOST_HAS_MPTASKS)
# include <Multiprocessing.h>
#endif
namespace boost {
namespace detail {
class BOOST_THREAD_DECL tss : private noncopyable
{
public:
tss(boost::function1<void, void*>* pcleanup) {
if (pcleanup == 0) throw boost::thread_resource_error();
try
{
init(pcleanup);
}
catch (...)
{
delete pcleanup;
throw boost::thread_resource_error();
}
}
void* get() const;
void set(void* value);
void cleanup(void* p);
private:
unsigned int m_slot; //This is a "pseudo-slot", not a native slot
void init(boost::function1<void, void*>* pcleanup);
};
#if defined(BOOST_HAS_MPTASKS)
void thread_cleanup();
#endif
template <typename T>
struct tss_adapter
{
template <typename F>
tss_adapter(const F& cleanup) : m_cleanup(cleanup) { }
void operator()(void* p) { m_cleanup(static_cast<T*>(p)); }
boost::function1<void, T*> m_cleanup;
};
} // namespace detail
template <typename T>
class thread_specific_ptr : private noncopyable
{
public:
thread_specific_ptr()
: m_tss(new boost::function1<void, void*>(
boost::detail::tss_adapter<T>(
&thread_specific_ptr<T>::cleanup)))
{
}
thread_specific_ptr(void (*clean)(T*))
: m_tss(new boost::function1<void, void*>(
boost::detail::tss_adapter<T>(clean)))
{
}
~thread_specific_ptr() { reset(); }
T* get() const { return static_cast<T*>(m_tss.get()); }
T* operator->() const { return get(); }
T& operator*() const { return *get(); }
T* release() { T* temp = get(); if (temp) m_tss.set(0); return temp; }
void reset(T* p=0)
{
T* cur = get();
if (cur == p) return;
m_tss.set(p);
if (cur) m_tss.cleanup(cur);
}
private:
static void cleanup(T* p) { delete p; }
detail::tss m_tss;
};
} // namespace boost
#endif //BOOST_TSS_WEK070601_HPP
// Change Log:
// 6 Jun 01
// WEKEMPF Initial version.
// 30 May 02 WEKEMPF
// Added interface to set specific cleanup handlers.
// Removed TLS slot limits from most implementations.
// 22 Mar 04 GlassfordM for WEKEMPF
// Fixed: thread_specific_ptr::reset() doesn't check error returned
// by tss::set(); tss::set() now throws if it fails.
// Fixed: calling thread_specific_ptr::reset() or
// thread_specific_ptr::release() causes double-delete: once on
// reset()/release() and once on ~thread_specific_ptr().

View File

@@ -1,59 +0,0 @@
// Copyright (C) 2001-2003
// 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.
#ifndef BOOST_XTIME_WEK070601_HPP
#define BOOST_XTIME_WEK070601_HPP
#include <boost/thread/detail/config.hpp>
#include <boost/cstdint.hpp>
namespace boost {
enum xtime_clock_types
{
TIME_UTC=1
// TIME_TAI,
// TIME_MONOTONIC,
// TIME_PROCESS,
// TIME_THREAD,
// TIME_LOCAL,
// TIME_SYNC,
// TIME_RESOLUTION
};
struct xtime
{
#if defined(BOOST_NO_INT64_T)
typedef int_fast32_t xtime_sec_t; //INT_FAST32_MIN <= sec <= INT_FAST32_MAX
#else
typedef int_fast64_t xtime_sec_t; //INT_FAST64_MIN <= sec <= INT_FAST64_MAX
#endif
typedef int_fast32_t xtime_nsec_t; //0 <= xtime.nsec < NANOSECONDS_PER_SECOND
xtime_sec_t sec;
xtime_nsec_t nsec;
};
int BOOST_THREAD_DECL xtime_get(struct xtime* xtp, int clock_type);
inline int xtime_cmp(const xtime& xt1, const xtime& xt2)
{
if (xt1.sec == xt2.sec)
return (int)(xt1.nsec - xt2.nsec);
else
return (xt1.sec > xt2.sec) ? 1 : -1;
}
} // namespace boost
#endif //BOOST_XTIME_WEK070601_HPP

View File

@@ -11,17 +11,11 @@
#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

View File

@@ -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 || res == EBUSY);
assert(res == 0);
if (res == 0)
{

View File

@@ -220,7 +220,6 @@ 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);
@@ -368,9 +367,4 @@ void thread_group::join_all()
}
}
int thread_group::size()
{
return m_threads.size();
}
} // namespace boost

View File

@@ -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;

View File

@@ -19,27 +19,18 @@
import testing ;
project
: requirements <library>../../test/build//boost_unit_test_framework
: requirements <library>../build//boost_thread
<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"
: [ 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 ]
: [ 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 ]
;
}

View File

@@ -48,7 +48,7 @@ void test_barrier()
g.join_all();
BOOST_CHECK(global_parameter == 5);
BOOST_TEST(global_parameter == 5);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])

View File

@@ -17,6 +17,7 @@
#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>

View File

@@ -9,8 +9,6 @@
// 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>
@@ -19,767 +17,314 @@
#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;
TS_CHECK (boost::TIME_UTC == boost::xtime_get(&ret, boost::TIME_UTC));
BOOST_TEST(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 &param2
)
: func_(func)
, param1_(param1)
, param2_(param2)
{}
void operator()() const
{
func_(param1_, param2_);
}
thread_adapter(void (*func)(void*,RW &), void* param1,RW &param2)
: _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 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)
{}
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;
int id_;
int wait_for_lock_secs_;
int sleep_with_lock_secs_;
bool test_promotion_and_demotion_;
int value_;
RW& rw_;
RW& m_rw; // Reader/Writer mutex
};
// 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)
{
try
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())
{
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_read_write_lock l(
rw,
pdata->test_promotion_and_demotion_
? boost::read_write_lock_state::read_locked
: boost::read_write_lock_state::write_locked
);
boost::thread::sleep(xsecs(3));
shared_val += 10;
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;
}
pdata->m_value = shared_val;
}
catch(...)
}
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())
{
TS_CHECK_MSG(false, "plain_writer() exception!");
throw;
pdata->m_value = shared_val;
}
}
template<typename RW>
void plain_reader(void* arg, RW& rw)
void timed_writer(void *arg,RW &rw)
{
try
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))
{
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_);
boost::thread::sleep(xsecs(3));
shared_val += 10;
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;
pdata->m_value = shared_val;
}
}
template<typename RW>
void try_writer(void* arg, RW& rw)
void timed_reader(void *arg,RW &rw)
{
try
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))
{
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;
pdata->m_value = shared_val;
}
}
template<typename RW>
void try_reader(void*arg, RW& rw)
void dump_times(const char *prefix,data<RW> *pdata)
{
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;
}
std::cout << " " << prefix << pdata->m_id <<
" In:" << pdata->m_start.LowPart <<
" Holding:" << pdata->m_holding.LowPart <<
" Out: " << pdata->m_end.LowPart << std::endl;
}
template<typename 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)
void test_plain_read_write_mutex(RW &rw)
{
shared_val = 0;
data1.value_ = k_data_init;
data2.value_ = k_data_init;
data3.value_ = k_data_init;
data4.value_ = k_data_init;
}
data<RW> r1(1,rw);
data<RW> r2(2,rw);
data<RW> w1(1,rw);
data<RW> w2(2,rw);
bool shared_test_writelocked = false;
bool shared_test_readlocked = false;
bool shared_test_unlocked = false;
// Writer one launches, holds the lock for 3 seconds.
boost::thread tw1(thread_adapter<RW>(plain_writer,&w1,rw));
template<typename RW>
void run_try_tests(void* arg, RW& rw)
{
try
// 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)
{
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();
}
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);
}
catch(...)
else if (rw.policy() == boost::read_write_scheduling_policy::reader_priority)
{
TS_CHECK_MSG(false, "run_try_tests() exception!");
throw;
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));
}
}
template<typename RW>
void test_plain_read_write_mutex(RW& rw, bool test_promotion_and_demotion)
void test_try_read_write_mutex(RW &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);
data<RW> r1(1,rw);
data<RW> w1(2,rw);
data<RW> w2(3,rw);
//Write-lock the mutex and queue up other readers and writers
// We start with some specialized tests for "try" behavior
typename RW::scoped_read_write_lock l(rw, boost::read_write_lock_state::write_locked);
shared_val = 0;
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));
// Writer one launches, holds the lock for 3 seconds.
boost::thread::sleep(xsecs(1));
boost::thread tw1(thread_adapter<RW>(try_writer,&w1,rw));
//At this point, neither queued readers nor queued writers should have obtained access
// 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));
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);
// Writer two launches in the same timeframe.
boost::thread tw2(thread_adapter<RW>(try_writer,&w2,rw));
if (test_promotion_and_demotion)
{
l.demote();
boost::thread::sleep(xsecs(1));
//:boost::thread tr3(thread_adapter<RW>(plain_reader, &r3, rw));
tw2.join();
tr1.join();
tw1.join();
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();
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
tr2.join();
tr1.join();
tw2.join();
tw1.join();
// 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);
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_try_read_write_mutex(RW& rw, bool test_promotion_and_demotion)
void test_timed_read_write_mutex(RW &rw)
{
//Repeat the plain tests with the try lock.
//This is important to verify that try locks are proper
//read_write_mutexes as well.
data<RW> r1(1,rw,1);
data<RW> r2(2,rw,3);
data<RW> w1(3,rw,3);
data<RW> w2(4,rw,1);
test_plain_read_write_mutex(rw, test_promotion_and_demotion);
// We begin with some specialized tests for "timed" behavior
//Verify try_* operations with write-locked mutex
{
typename RW::scoped_try_read_write_lock l(rw, boost::read_write_lock_state::write_locked);
shared_val = 0;
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();
}
// Writer one will hold the lock for 3 seconds.
boost::thread tw1(thread_adapter<RW>(timed_writer,&w1,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();
}
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 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();
}
}
// 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.
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.
boost::thread tr1(thread_adapter<RW>(timed_reader,&r1,rw));
boost::thread tr2(thread_adapter<RW>(timed_reader,&r2,rw));
test_try_read_write_mutex(rw, test_promotion_and_demotion);
//:More tests here
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);
}
} // namespace
void do_test_read_write_mutex(bool test_promotion_and_demotion)
void test_read_write_mutex()
{
//Run every test for each scheduling policy
for(int i = (int) boost::read_write_scheduling_policy::writer_priority;
int i;
for(i = (int) boost::read_write_scheduling_policy::writer_priority;
i <= (int) boost::read_write_scheduling_policy::alternating_single_read;
i++)
{
std::cout << "plain test, sp=" << i
<< (test_promotion_and_demotion ? " with promotion & demotion" : " without promotion & demotion")
<< "\n";
std::cout.flush();
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));
{
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 << "plain test, sp=" << i << "\n";
test_plain_read_write_mutex(plain_rw);
std::cout << "try test, sp=" << i
<< (test_promotion_and_demotion ? " with promotion & demotion" : " without promotion & demotion")
<< "\n";
std::cout.flush();
std::cout << "try test, sp=" << i << "\n";
test_try_read_write_mutex(try_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);
}
std::cout << "timed test, sp=" << i << "\n";
test_timed_read_write_mutex(timed_rw);
}
}
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 =

View File

@@ -29,9 +29,9 @@ void simple_thread()
void comparison_thread(boost::thread* parent)
{
boost::thread thrd;
BOOST_CHECK(thrd != *parent);
BOOST_TEST(thrd != *parent);
boost::thread thrd2;
BOOST_CHECK(thrd == thrd2);
BOOST_TEST(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, 2));
BOOST_CHECK(in_range(xt));
}
void do_test_creation()

View File

@@ -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;
if (boost::TIME_UTC != boost::xtime_get (&xt, boost::TIME_UTC))
BOOST_ERROR ("boost::xtime_get != boost::TIME_UTC");
BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC),
static_cast<int>(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 thread_binder
class binder
{
public:
thread_binder(const F& func, const T& param)
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>
thread_binder<F, T> bind(const F& func, const T& param)
binder<F, T> bind(const F& func, const T& param)
{
return thread_binder<F, T>(func, param);
return binder<F, T>(func, param);
}
} // namespace