2
0
mirror of https://github.com/boostorg/thread.git synced 2026-02-03 09:42:16 +00:00

Compare commits

..

1 Commits

Author SHA1 Message Date
Beman Dawes
560e8320d1 Branch for development of boost.system related changes
[SVN r40931]
2007-11-08 14:20:16 +00:00
85 changed files with 1672 additions and 2975 deletions

2
build/.cvsignore Normal file
View File

@@ -0,0 +1,2 @@
bin*
*.pdb

View File

@@ -157,7 +157,6 @@ rule usage-requirements ( properties * )
rule requirements ( properties * )
{
local result ;
if <threadapi>pthread in $(properties)
{
result += <define>BOOST_THREAD_POSIX ;
@@ -181,6 +180,8 @@ alias thread_sources
: ## win32 sources ##
win32/thread.cpp
win32/exceptions.cpp
win32/tss.cpp
win32/tss_hooks.cpp
win32/tss_dll.cpp
win32/tss_pe.cpp
: ## requirements ##
@@ -191,7 +192,7 @@ alias thread_sources
: ## pthread sources ##
pthread/thread.cpp
pthread/exceptions.cpp
pthread/once.cpp
pthread/tss.cpp
: ## requirements ##
<threadapi>pthread
;
@@ -202,7 +203,5 @@ lib boost_thread
: thread_sources
: <conditional>@requirements
:
: <link>shared:<define>BOOST_THREAD_USE_DLL=1
<link>static:<define>BOOST_THREAD_USE_LIB=1
<conditional>@usage-requirements
: <conditional>@usage-requirements
;

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
-->
<section id="thread.acknowledgements"
last-revision="$Date$">

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
-->
<header name="boost/thread/barrier.hpp"
last-revision="$Date$">

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
-->
<bibliography id="thread.bibliography"
last-revision="$Date$">

View File

@@ -7,7 +7,7 @@
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Copyright (c) 2007 Roland Schwarz
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
-->
<section id="thread.build" last-revision="$Date$">
<title>Build</title>

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
-->
<section id="thread.concepts" last-revision="$Date$">
<title>Concepts</title>

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
-->
<header name="boost/thread/condition.hpp"
last-revision="$Date$">

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
-->
<section id="thread.configuration" last-revision="$Date$">
<title>Configuration</title>

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
-->
<section id="thread.design" last-revision="$Date$">
<title>Design</title>

View File

@@ -1,6 +1,6 @@
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
-->
<!ENTITY Boost "<emphasis role='bold'>Boost</emphasis>">
<!ENTITY Boost.Thread "<emphasis role='bold'>Boost.Thread</emphasis>">

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
-->
<header name="boost/thread/exceptions.hpp"
last-revision="$Date$">

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
-->
<section id="thread.faq" last-revision="$Date$">
<title>Frequently Asked Questions</title>

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
-->
<glossary id="thread.glossary" last-revision="$Date$">
<title>Glossary</title>

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
-->
<section id="thread.implementation_notes" last-revision="$Date$">
<title>Implementation Notes</title>

View File

@@ -1,6 +1,6 @@
<!-- Copyright (c) 2002-2003 Beman Dawes, William E. Kempf.
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
-->
<html>
<head>

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
-->
<header name="boost/thread/mutex.hpp"
last-revision="$Date$">

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
-->
<header name="boost/thread/once.hpp"
last-revision="$Date$">

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
-->
<section id="thread.overview" last-revision="$Date$">
<title>Overview</title>

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
-->
<section id="thread.rationale" last-revision="$Date$">
<title>Rationale</title>

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
-->
<header name="boost/thread/read_write_mutex.hpp"
last-revision="$Date$">

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
-->
<header name="boost/thread/recursive_mutex.hpp"
last-revision="$Date$">

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
-->
<library-reference id="thread.reference"
last-revision="$Date$"

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
-->
<section id="thread.release_notes" last-revision="$Date$">
<title>Release Notes</title>

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
-->
<header name="boost/thread/thread.hpp"
last-revision="$Date$">

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
-->
<library name="Thread" dirname="thread" id="thread"
last-revision="$Date$"
@@ -25,7 +25,7 @@ xmlns:xi="http://www.w3.org/2001/XInclude">
</copyright>
<legalnotice>
<para>Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)</para>
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)</para>
</legalnotice>
<librarypurpose>Portable C++ multi-threading</librarypurpose>
<librarycategory name="category:concurrent" />

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
-->
<header name="boost/thread/tss.hpp"
last-revision="$Date$">

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
-->
<header name="boost/thread/xtime.hpp"
last-revision="$Date$">

2
example/.cvsignore Normal file
View File

@@ -0,0 +1,2 @@
bin
*.pdb

View File

@@ -4,8 +4,6 @@
// 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 www.boost.org/libs/thread for documentation.
#if !defined(BOOST_THREAD_WEK01082003_HPP)
#define BOOST_THREAD_WEK01082003_HPP

View File

@@ -10,12 +10,6 @@
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/thread/detail/platform.hpp>
#if defined(BOOST_THREAD_PLATFORM_WIN32)
#include <boost/thread/win32/condition_variable.hpp>
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
#include <boost/thread/pthread/condition_variable.hpp>
#else
#error "Boost threads unavailable on this platform"
#endif
#include BOOST_THREAD_PLATFORM(condition_variable.hpp)
#endif

View File

@@ -17,7 +17,8 @@
# pragma warn -8066 // Unreachable code
#endif
#include "platform.hpp"
// insist on threading support being available:
#include <boost/config/requires_threads.hpp>
// compatibility with the rest of Boost's auto-linking code:
#if defined(BOOST_THREAD_DYN_DLL) || defined(BOOST_ALL_DYN_LINK)
@@ -30,7 +31,7 @@
#elif defined(BOOST_THREAD_USE_DLL) //Use dll
#elif defined(BOOST_THREAD_USE_LIB) //Use lib
#else //Use default
# if defined(BOOST_THREAD_PLATFORM_WIN32)
# 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

View File

@@ -8,23 +8,25 @@
namespace boost
{
namespace detail
template<typename T>
struct move_t
{
template<typename T>
struct thread_move_t
{
T& t;
thread_move_t(T& t_):
t(t_)
{}
T& t;
move_t(T& t_):
t(t_)
{}
T* operator->() const
{
return &t;
}
};
T* operator->() const
{
return &t;
}
};
template<typename T>
move_t<T> move(T& t)
{
return move_t<T>(t);
}
}

View File

@@ -1,5 +1,4 @@
// Copyright 2006 Roland Schwarz.
// (C) Copyright 2007 Anthony Williams
// 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)
@@ -57,15 +56,17 @@
// available the preprocessor will fail with a diagnostic message.
#if defined(BOOST_THREAD_POSIX)
# define BOOST_THREAD_PLATFORM_PTHREAD
# define BOOST_THREAD_PPFX pthread
#else
# if defined(BOOST_THREAD_WIN32)
# define BOOST_THREAD_PLATFORM_WIN32
# define BOOST_THREAD_PPFX win32
# elif defined(BOOST_HAS_PTHREADS)
# define BOOST_THREAD_PLATFORM_PTHREAD
# define BOOST_THREAD_PPFX pthread
# else
# error "Sorry, no boost threads are available for this platform."
# endif
#endif
#define BOOST_THREAD_PLATFORM(header) <boost/thread/BOOST_THREAD_PPFX/header>
#endif // BOOST_THREAD_RS06040501_HPP

View File

@@ -67,7 +67,7 @@
//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

View File

@@ -86,32 +86,21 @@ namespace boost
{
timed_lock(target_time);
}
unique_lock(detail::thread_move_t<unique_lock<Mutex> > other):
unique_lock(boost::move_t<unique_lock<Mutex> > other):
m(other->m),is_locked(other->is_locked)
{
other->is_locked=false;
other->m=0;
}
unique_lock(detail::thread_move_t<upgrade_lock<Mutex> > other);
unique_lock(boost::move_t<upgrade_lock<Mutex> > other);
operator detail::thread_move_t<unique_lock<Mutex> >()
{
return move();
}
detail::thread_move_t<unique_lock<Mutex> > move()
{
return detail::thread_move_t<unique_lock<Mutex> >(*this);
}
unique_lock& operator=(detail::thread_move_t<unique_lock<Mutex> > other)
unique_lock& operator=(boost::move_t<unique_lock<Mutex> > other)
{
unique_lock temp(other);
swap(temp);
return *this;
}
unique_lock& operator=(detail::thread_move_t<upgrade_lock<Mutex> > other)
unique_lock& operator=(boost::move_t<upgrade_lock<Mutex> > other)
{
unique_lock temp(other);
swap(temp);
@@ -123,7 +112,7 @@ namespace boost
std::swap(m,other.m);
std::swap(is_locked,other.is_locked);
}
void swap(detail::thread_move_t<unique_lock<Mutex> > other)
void swap(boost::move_t<unique_lock<Mutex> > other)
{
std::swap(m,other->m);
std::swap(is_locked,other->is_locked);
@@ -207,18 +196,6 @@ namespace boost
friend class upgrade_lock<Mutex>;
};
template<typename Mutex>
inline detail::thread_move_t<unique_lock<Mutex> > move(unique_lock<Mutex> & x)
{
return x.move();
}
template<typename Mutex>
inline detail::thread_move_t<unique_lock<Mutex> > move(detail::thread_move_t<unique_lock<Mutex> > x)
{
return x;
}
template<typename Mutex>
class shared_lock
{
@@ -251,13 +228,13 @@ namespace boost
timed_lock(target_time);
}
shared_lock(detail::thread_move_t<shared_lock<Mutex> > other):
shared_lock(boost::move_t<shared_lock<Mutex> > other):
m(other->m),is_locked(other->is_locked)
{
other->is_locked=false;
}
shared_lock(detail::thread_move_t<unique_lock<Mutex> > other):
shared_lock(boost::move_t<unique_lock<Mutex> > other):
m(other->m),is_locked(other->is_locked)
{
other->is_locked=false;
@@ -267,7 +244,7 @@ namespace boost
}
}
shared_lock(detail::thread_move_t<upgrade_lock<Mutex> > other):
shared_lock(boost::move_t<upgrade_lock<Mutex> > other):
m(other->m),is_locked(other->is_locked)
{
other->is_locked=false;
@@ -277,32 +254,21 @@ namespace boost
}
}
operator detail::thread_move_t<shared_lock<Mutex> >()
{
return move();
}
detail::thread_move_t<shared_lock<Mutex> > move()
{
return detail::thread_move_t<shared_lock<Mutex> >(*this);
}
shared_lock& operator=(detail::thread_move_t<shared_lock<Mutex> > other)
shared_lock& operator=(boost::move_t<shared_lock<Mutex> > other)
{
shared_lock temp(other);
swap(temp);
return *this;
}
shared_lock& operator=(detail::thread_move_t<unique_lock<Mutex> > other)
shared_lock& operator=(boost::move_t<unique_lock<Mutex> > other)
{
shared_lock temp(other);
swap(temp);
return *this;
}
shared_lock& operator=(detail::thread_move_t<upgrade_lock<Mutex> > other)
shared_lock& operator=(boost::move_t<upgrade_lock<Mutex> > other)
{
shared_lock temp(other);
swap(temp);
@@ -375,19 +341,6 @@ namespace boost
};
template<typename Mutex>
inline detail::thread_move_t<shared_lock<Mutex> > move(shared_lock<Mutex> & x)
{
return x.move();
}
template<typename Mutex>
inline detail::thread_move_t<shared_lock<Mutex> > move(detail::thread_move_t<shared_lock<Mutex> > x)
{
return x;
}
template<typename Mutex>
class upgrade_lock
{
@@ -411,13 +364,13 @@ namespace boost
lock();
}
}
upgrade_lock(detail::thread_move_t<upgrade_lock<Mutex> > other):
upgrade_lock(boost::move_t<upgrade_lock<Mutex> > other):
m(other->m),is_locked(other->is_locked)
{
other->is_locked=false;
}
upgrade_lock(detail::thread_move_t<unique_lock<Mutex> > other):
upgrade_lock(boost::move_t<unique_lock<Mutex> > other):
m(other->m),is_locked(other->is_locked)
{
other->is_locked=false;
@@ -427,25 +380,14 @@ namespace boost
}
}
operator detail::thread_move_t<upgrade_lock<Mutex> >()
{
return move();
}
detail::thread_move_t<upgrade_lock<Mutex> > move()
{
return detail::thread_move_t<upgrade_lock<Mutex> >(*this);
}
upgrade_lock& operator=(detail::thread_move_t<upgrade_lock<Mutex> > other)
upgrade_lock& operator=(boost::move_t<upgrade_lock<Mutex> > other)
{
upgrade_lock temp(other);
swap(temp);
return *this;
}
upgrade_lock& operator=(detail::thread_move_t<unique_lock<Mutex> > other)
upgrade_lock& operator=(boost::move_t<unique_lock<Mutex> > other)
{
upgrade_lock temp(other);
swap(temp);
@@ -510,21 +452,8 @@ namespace boost
friend class unique_lock<Mutex>;
};
template<typename Mutex>
inline detail::thread_move_t<upgrade_lock<Mutex> > move(upgrade_lock<Mutex> & x)
{
return x.move();
}
template<typename Mutex>
inline detail::thread_move_t<upgrade_lock<Mutex> > move(detail::thread_move_t<upgrade_lock<Mutex> > x)
{
return x;
}
template<typename Mutex>
unique_lock<Mutex>::unique_lock(detail::thread_move_t<upgrade_lock<Mutex> > other):
unique_lock<Mutex>::unique_lock(boost::move_t<upgrade_lock<Mutex> > other):
m(other->m),is_locked(other->is_locked)
{
other->is_locked=false;
@@ -545,23 +474,23 @@ namespace boost
upgrade_to_unique_lock& operator=(upgrade_to_unique_lock&);
public:
explicit upgrade_to_unique_lock(upgrade_lock<Mutex>& m_):
source(&m_),exclusive(move(*source))
source(&m_),exclusive(boost::move(*source))
{}
~upgrade_to_unique_lock()
{
if(source)
{
*source=move(exclusive);
*source=boost::move(exclusive);
}
}
upgrade_to_unique_lock(detail::thread_move_t<upgrade_to_unique_lock<Mutex> > other):
source(other->source),exclusive(move(other->exclusive))
upgrade_to_unique_lock(boost::move_t<upgrade_to_unique_lock<Mutex> > other):
source(other->source),exclusive(boost::move(other->exclusive))
{
other->source=0;
}
upgrade_to_unique_lock& operator=(detail::thread_move_t<upgrade_to_unique_lock<Mutex> > other)
upgrade_to_unique_lock& operator=(boost::move_t<upgrade_to_unique_lock<Mutex> > other)
{
upgrade_to_unique_lock temp(other);
swap(temp);
@@ -586,7 +515,6 @@ namespace boost
return exclusive.owns_lock();
}
};
}
#endif

View File

@@ -10,12 +10,6 @@
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/thread/detail/platform.hpp>
#if defined(BOOST_THREAD_PLATFORM_WIN32)
#include <boost/thread/win32/mutex.hpp>
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
#include <boost/thread/pthread/mutex.hpp>
#else
#error "Boost threads unavailable on this platform"
#endif
#include BOOST_THREAD_PLATFORM(mutex.hpp)
#endif

View File

@@ -10,13 +10,7 @@
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/thread/detail/platform.hpp>
#if defined(BOOST_THREAD_PLATFORM_WIN32)
#include <boost/thread/win32/once.hpp>
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
#include <boost/thread/pthread/once.hpp>
#else
#error "Boost threads unavailable on this platform"
#endif
#include BOOST_THREAD_PLATFORM(once.hpp)
namespace boost
{

View File

@@ -5,9 +5,11 @@
// http://www.boost.org/LICENSE_1_0.txt)
// (C) Copyright 2007 Anthony Williams
#include <boost/thread/mutex.hpp>
#include <limits.h>
#include <boost/assert.hpp>
#include <algorithm>
#include <boost/thread/thread_time.hpp>
#include <pthread.h>
#include "timespec.hpp"
#include "pthread_mutex_scoped_lock.hpp"
@@ -143,23 +145,11 @@ namespace boost
while (!pred())
{
if(!timed_wait(m, wait_until))
return pred();
return false;
}
return true;
}
template<typename lock_type,typename predicate_type>
bool timed_wait(lock_type& m,xtime const& wait_until,predicate_type pred)
{
return timed_wait(m,system_time(wait_until),pred);
}
template<typename lock_type,typename duration_type,typename predicate_type>
bool timed_wait(lock_type& m,duration_type const& wait_duration,predicate_type pred)
{
return timed_wait(m,get_system_time()+wait_duration,pred);
}
void notify_one()
{
boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);

View File

@@ -6,10 +6,8 @@
// (C) Copyright 2007 Anthony Williams
#include <pthread.h>
#include <boost/thread/mutex.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/thread_time.hpp>
#include <boost/thread/xtime.hpp>
namespace boost
{
@@ -41,23 +39,11 @@ namespace boost
while (!pred())
{
if(!timed_wait(m, wait_until))
return pred();
return false;
}
return true;
}
template<typename predicate_type>
bool timed_wait(unique_lock<mutex>& m,xtime const& wait_until,predicate_type pred)
{
return timed_wait(m,system_time(wait_until),pred);
}
template<typename duration_type,typename predicate_type>
bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration,predicate_type pred)
{
return timed_wait(m,get_system_time()+wait_duration,pred);
}
void notify_one();
void notify_all();
};

View File

@@ -14,72 +14,42 @@
#include <pthread.h>
#include <boost/assert.hpp>
#include "pthread_mutex_scoped_lock.hpp"
#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
#include <boost/cstdint.hpp>
namespace boost {
struct once_flag
{
boost::uintmax_t epoch;
pthread_mutex_t mutex;
unsigned long flag;
};
namespace detail
{
BOOST_THREAD_DECL boost::uintmax_t& get_once_per_thread_epoch();
BOOST_THREAD_DECL extern boost::uintmax_t once_global_epoch;
BOOST_THREAD_DECL extern pthread_mutex_t once_epoch_mutex;
BOOST_THREAD_DECL extern pthread_cond_t once_epoch_cv;
}
#define BOOST_ONCE_INITIAL_FLAG_VALUE 0
#define BOOST_ONCE_INIT {BOOST_ONCE_INITIAL_FLAG_VALUE}
#define BOOST_ONCE_INIT {PTHREAD_MUTEX_INITIALIZER,0}
// Based on Mike Burrows fast_pthread_once algorithm as described in
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2444.html
template<typename Function>
void call_once(once_flag& flag,Function f)
{
static boost::uintmax_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE;
static boost::uintmax_t const being_initialized=uninitialized_flag+1;
boost::uintmax_t const epoch=flag.epoch;
boost::uintmax_t& this_thread_epoch=detail::get_once_per_thread_epoch();
if(epoch<this_thread_epoch)
{
pthread::pthread_mutex_scoped_lock lk(&detail::once_epoch_mutex);
unsigned long const function_complete_flag_value=0xc15730e2ul;
while(flag.epoch<=being_initialized)
#ifdef BOOST_PTHREAD_HAS_ATOMICS
if(::boost::detail::interlocked_read_acquire(&flag.flag)!=function_complete_flag_value)
{
#endif
pthread::pthread_mutex_scoped_lock const lock(&flag.mutex);
if(flag.flag!=function_complete_flag_value)
{
if(flag.epoch==uninitialized_flag)
{
flag.epoch=being_initialized;
try
{
pthread::pthread_mutex_scoped_unlock relocker(&detail::once_epoch_mutex);
f();
}
catch(...)
{
flag.epoch=uninitialized_flag;
BOOST_VERIFY(!pthread_cond_broadcast(&detail::once_epoch_cv));
throw;
}
flag.epoch=--detail::once_global_epoch;
BOOST_VERIFY(!pthread_cond_broadcast(&detail::once_epoch_cv));
}
else
{
while(flag.epoch==being_initialized)
{
BOOST_VERIFY(!pthread_cond_wait(&detail::once_epoch_cv,&detail::once_epoch_mutex));
}
}
f();
#ifdef BOOST_PTHREAD_HAS_ATOMICS
::boost::detail::interlocked_write_release(&flag.flag,function_complete_flag_value);
#else
flag.flag=function_complete_flag_value;
#endif
}
this_thread_epoch=detail::once_global_epoch;
#ifdef BOOST_PTHREAD_HAS_ATOMICS
}
#endif
}
}
#endif

View File

@@ -28,22 +28,6 @@ namespace boost
}
};
class pthread_mutex_scoped_unlock
{
pthread_mutex_t* m;
public:
explicit pthread_mutex_scoped_unlock(pthread_mutex_t* m_):
m(m_)
{
BOOST_VERIFY(!pthread_mutex_unlock(m));
}
~pthread_mutex_scoped_unlock()
{
BOOST_VERIFY(!pthread_mutex_lock(m));
}
};
}
}

View File

@@ -40,62 +40,44 @@ namespace boost
{
class thread_id
{
private:
detail::thread_data_ptr thread_data;
thread_id(detail::thread_data_ptr thread_data_):
thread_data(thread_data_)
{}
boost::optional<pthread_t> id;
friend class boost::thread;
friend thread_id this_thread::get_id();
public:
thread_id():
thread_data()
thread_id(pthread_t id_):
id(id_)
{}
public:
thread_id()
{}
bool operator==(const thread_id& y) const
{
return thread_data==y.thread_data;
return (id && y.id) && (pthread_equal(*id,*y.id)!=0);
}
bool operator!=(const thread_id& y) const
{
return thread_data!=y.thread_data;
}
bool operator<(const thread_id& y) const
{
return thread_data<y.thread_data;
}
bool operator>(const thread_id& y) const
{
return y.thread_data<thread_data;
}
bool operator<=(const thread_id& y) const
{
return !(y.thread_data<thread_data);
}
bool operator>=(const thread_id& y) const
{
return !(thread_data<y.thread_data);
return !(*this==y);
}
template<class charT, class traits>
friend std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, const thread_id& x)
{
if(x.thread_data)
if(x.id)
{
return os<<x.thread_data;
return os<<*x.id;
}
else
{
return os<<"{Not-any-thread}";
}
}
};
}
@@ -115,7 +97,7 @@ namespace boost
thread_data(F f_):
f(f_)
{}
thread_data(detail::thread_move_t<F> f_):
thread_data(boost::move_t<F> f_):
f(f_)
{}
@@ -126,13 +108,13 @@ namespace boost
};
mutable boost::mutex thread_info_mutex;
detail::thread_data_ptr thread_info;
boost::shared_ptr<detail::thread_data_base> thread_info;
void start_thread();
explicit thread(detail::thread_data_ptr data);
explicit thread(boost::shared_ptr<detail::thread_data_base> data);
detail::thread_data_ptr get_thread_info() const;
boost::shared_ptr<detail::thread_data_base> get_thread_info() const;
public:
thread();
@@ -145,16 +127,16 @@ namespace boost
start_thread();
}
template <class F>
thread(detail::thread_move_t<F> f):
thread(boost::move_t<F> f):
thread_info(new thread_data<F>(f))
{
start_thread();
}
thread(detail::thread_move_t<thread> x);
thread& operator=(detail::thread_move_t<thread> x);
operator detail::thread_move_t<thread>();
detail::thread_move_t<thread> move();
explicit thread(boost::move_t<thread> x);
thread& operator=(boost::move_t<thread> x);
operator boost::move_t<thread>();
boost::move_t<thread> move();
void swap(thread& x);
@@ -187,17 +169,6 @@ namespace boost
bool interruption_requested() const;
};
inline detail::thread_move_t<thread> move(thread& x)
{
return x.move();
}
inline detail::thread_move_t<thread> move(detail::thread_move_t<thread> x)
{
return x;
}
template<typename F>
struct thread::thread_data<boost::reference_wrapper<F> >:
detail::thread_data_base
@@ -237,19 +208,22 @@ namespace boost
~restore_interruption();
};
BOOST_THREAD_DECL thread::id get_id();
BOOST_THREAD_DECL inline thread::id get_id()
{
return thread::id(pthread_self());
}
BOOST_THREAD_DECL void interruption_point();
BOOST_THREAD_DECL bool interruption_enabled();
BOOST_THREAD_DECL bool interruption_requested();
inline void yield()
BOOST_THREAD_DECL inline void yield()
{
thread::yield();
}
template<typename TimeDuration>
inline void sleep(TimeDuration const& rel_time)
BOOST_THREAD_DECL inline void sleep(TimeDuration const& rel_time)
{
thread::sleep(get_system_time()+rel_time);
}
@@ -303,7 +277,6 @@ namespace boost
void add_thread(thread* thrd);
void remove_thread(thread* thrd);
void join_all();
void interrupt_all();
int size() const;
private:

View File

@@ -7,7 +7,6 @@
#include <boost/thread/detail/config.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/optional.hpp>
#include <pthread.h>
@@ -21,15 +20,10 @@ namespace boost
namespace detail
{
struct thread_exit_callback_node;
struct tss_data_node;
struct thread_data_base;
typedef boost::shared_ptr<thread_data_base> thread_data_ptr;
struct thread_data_base:
enable_shared_from_this<thread_data_base>
struct thread_data_base
{
thread_data_ptr self;
boost::shared_ptr<thread_data_base> self;
pthread_t thread_handle;
boost::mutex data_mutex;
boost::condition_variable done_condition;
@@ -39,14 +33,13 @@ namespace boost
bool join_started;
bool joined;
boost::detail::thread_exit_callback_node* thread_exit_callbacks;
boost::detail::tss_data_node* tss_data;
bool interrupt_enabled;
bool interrupt_requested;
pthread_cond_t* current_cond;
thread_data_base():
done(false),join_started(false),joined(false),
thread_exit_callbacks(0),tss_data(0),
thread_exit_callbacks(0),
interrupt_enabled(true),
interrupt_requested(false),
current_cond(0)

View File

@@ -1,103 +0,0 @@
#ifndef BOOST_THREAD_PTHREAD_TSS_HPP
#define BOOST_THREAD_PTHREAD_TSS_HPP
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// (C) Copyright 2007 Anthony Williams
#include <boost/thread/detail/config.hpp>
#include <boost/shared_ptr.hpp>
namespace boost
{
namespace detail
{
struct tss_cleanup_function
{
virtual ~tss_cleanup_function()
{}
virtual void operator()(void* data)=0;
};
BOOST_THREAD_DECL void set_tss_data(void const* key,boost::shared_ptr<tss_cleanup_function> func,void* tss_data,bool cleanup_existing);
BOOST_THREAD_DECL void* get_tss_data(void const* key);
}
template <typename T>
class thread_specific_ptr
{
private:
thread_specific_ptr(thread_specific_ptr&);
thread_specific_ptr& operator=(thread_specific_ptr&);
struct delete_data:
detail::tss_cleanup_function
{
void operator()(void* data)
{
delete static_cast<T*>(data);
}
};
struct run_custom_cleanup_function:
detail::tss_cleanup_function
{
void (*cleanup_function)(T*);
explicit run_custom_cleanup_function(void (*cleanup_function_)(T*)):
cleanup_function(cleanup_function_)
{}
void operator()(void* data)
{
cleanup_function(static_cast<T*>(data));
}
};
boost::shared_ptr<detail::tss_cleanup_function> cleanup;
public:
thread_specific_ptr():
cleanup(new delete_data)
{}
explicit thread_specific_ptr(void (*func_)(T*)):
cleanup(new run_custom_cleanup_function(func_))
{}
~thread_specific_ptr()
{
reset();
}
T* get() const
{
return static_cast<T*>(detail::get_tss_data(this));
}
T* operator->() const
{
return get();
}
T& operator*() const
{
return *get();
}
T* release()
{
T* const temp=get();
detail::set_tss_data(this,0,0,false);
return temp;
}
void reset(T* new_value=0)
{
T* const current_value=get();
if(current_value!=new_value)
{
detail::set_tss_data(this,cleanup,new_value,true);
}
}
};
}
#endif

View File

@@ -10,12 +10,6 @@
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/thread/detail/platform.hpp>
#if defined(BOOST_THREAD_PLATFORM_WIN32)
#include <boost/thread/win32/recursive_mutex.hpp>
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
#include <boost/thread/pthread/recursive_mutex.hpp>
#else
#error "Boost threads unavailable on this platform"
#endif
#include BOOST_THREAD_PLATFORM(recursive_mutex.hpp)
#endif

View File

@@ -10,12 +10,6 @@
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/thread/detail/platform.hpp>
#if defined(BOOST_THREAD_PLATFORM_WIN32)
#include <boost/thread/win32/shared_mutex.hpp>
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
#include <boost/thread/pthread/shared_mutex.hpp>
#else
#error "Boost threads unavailable on this platform"
#endif
#include BOOST_THREAD_PLATFORM(shared_mutex.hpp)
#endif

View File

@@ -10,13 +10,6 @@
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/thread/detail/platform.hpp>
#if defined(BOOST_THREAD_PLATFORM_WIN32)
#include <boost/thread/win32/thread.hpp>
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
#include <boost/thread/pthread/thread.hpp>
#else
#error "Boost threads unavailable on this platform"
#endif
#include BOOST_THREAD_PLATFORM(thread.hpp)
#endif

View File

@@ -1,18 +1,128 @@
// Copyright (C) 2007 Anthony Williams
// Copyright (C) 2001-2003 William E. Kempf
// Copyright (C) 2006 Roland Schwarz
//
// 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)
#ifndef BOOST_THREAD_TSS_HPP
#define BOOST_THREAD_TSS_HPP
#ifndef BOOST_TSS_WEK070601_HPP
#define BOOST_TSS_WEK070601_HPP
#include <boost/thread/detail/platform.hpp>
#if defined(BOOST_THREAD_PLATFORM_WIN32)
#include <boost/thread/win32/tss.hpp>
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
#include <boost/thread/pthread/tss.hpp>
#else
#error "Boost threads unavailable on this platform"
#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 {
// disable warnings about non dll import
// see: http://www.boost.org/more/separate_compilation.html#dlls
#ifdef BOOST_MSVC
# pragma warning(push)
# pragma warning(disable: 4251 4231 4660 4275)
#endif
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();
}
}
~tss();
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;
};
#ifdef BOOST_MSVC
# pragma warning(pop)
#endif
} // 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

@@ -56,12 +56,6 @@ namespace boost
long const current_thread_id=win32::GetCurrentThreadId();
return try_recursive_lock(current_thread_id) || try_timed_lock(current_thread_id,target);
}
template<typename Duration>
bool timed_lock(Duration const& timeout)
{
return timed_lock(get_system_time()+timeout);
}
long get_active_count()
{
return mutex.get_active_count();

View File

@@ -104,12 +104,6 @@ namespace boost
return true;
}
template<typename Duration>
bool timed_lock(Duration const& timeout)
{
return timed_lock(get_system_time()+timeout);
}
long get_active_count()
{
return ::boost::detail::interlocked_read_acquire(&active_count);

View File

@@ -13,7 +13,6 @@
#include <boost/thread/thread.hpp>
#include <boost/thread/thread_time.hpp>
#include "interlocked_read.hpp"
#include <boost/thread/xtime.hpp>
namespace boost
{
@@ -111,65 +110,54 @@ namespace boost
};
template<typename lock_type>
void start_wait_loop_first_time(relocker<lock_type>& locker,
detail::win32::handle_manager& local_wake_sem)
{
locker.unlock();
if(!wake_sem)
{
wake_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
BOOST_ASSERT(wake_sem);
}
local_wake_sem=detail::win32::duplicate_handle(wake_sem);
if(generations[0].notified)
{
shift_generations_down();
}
else if(!active_generation_count)
{
active_generation_count=1;
}
}
template<typename lock_type>
void start_wait_loop(relocker<lock_type>& locker,
detail::win32::handle_manager& local_wake_sem,
detail::win32::handle_manager& sem)
{
boost::mutex::scoped_lock internal_lock(internal_mutex);
detail::interlocked_write_release(&total_count,total_count+1);
if(!local_wake_sem)
{
start_wait_loop_first_time(locker,local_wake_sem);
}
if(!generations[0].semaphore)
{
generations[0].semaphore=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
BOOST_ASSERT(generations[0].semaphore);
}
++generations[0].count;
sem=detail::win32::duplicate_handle(generations[0].semaphore);
}
protected:
template<typename lock_type>
bool do_wait(lock_type& lock,timeout wait_until)
bool do_wait(lock_type& lock,::boost::system_time const& wait_until)
{
detail::win32::handle_manager local_wake_sem;
detail::win32::handle_manager sem;
bool first_loop=true;
bool woken=false;
relocker<lock_type> locker(lock);
while(!woken)
{
start_wait_loop(locker,local_wake_sem,sem);
if(!this_thread::interruptible_wait(sem,wait_until))
{
return false;
boost::mutex::scoped_lock internal_lock(internal_mutex);
detail::interlocked_write_release(&total_count,total_count+1);
if(first_loop)
{
locker.unlock();
if(!wake_sem)
{
wake_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
BOOST_ASSERT(wake_sem);
}
local_wake_sem=detail::win32::duplicate_handle(wake_sem);
if(generations[0].notified)
{
shift_generations_down();
}
else if(!active_generation_count)
{
active_generation_count=1;
}
first_loop=false;
}
if(!generations[0].semaphore)
{
generations[0].semaphore=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
BOOST_ASSERT(generations[0].semaphore);
}
++generations[0].count;
sem=detail::win32::duplicate_handle(generations[0].semaphore);
}
if(!this_thread::interruptible_wait(sem,::boost::detail::get_milliseconds_until(wait_until)))
{
break;
}
unsigned long const woken_result=detail::win32::WaitForSingleObject(local_wake_sem,0);
@@ -179,17 +167,6 @@ namespace boost
}
return woken;
}
template<typename lock_type,typename predicate_type>
bool do_wait(lock_type& m,timeout const& wait_until,predicate_type pred)
{
while (!pred())
{
if(!do_wait(m, wait_until))
return pred();
}
return true;
}
basic_condition_variable(const basic_condition_variable& other);
basic_condition_variable& operator=(const basic_condition_variable& other);
@@ -261,7 +238,7 @@ namespace boost
public:
void wait(unique_lock<mutex>& m)
{
do_wait(m,detail::timeout::sentinel());
do_wait(m,::boost::detail::get_system_time_sentinel());
}
template<typename predicate_type>
@@ -276,30 +253,15 @@ namespace boost
return do_wait(m,wait_until);
}
bool timed_wait(unique_lock<mutex>& m,boost::xtime const& wait_until)
{
return do_wait(m,system_time(wait_until));
}
template<typename duration_type>
bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration)
{
return do_wait(m,wait_duration.total_milliseconds());
}
template<typename predicate_type>
bool timed_wait(unique_lock<mutex>& m,boost::system_time const& wait_until,predicate_type pred)
{
return do_wait(m,wait_until,pred);
}
template<typename predicate_type>
bool timed_wait(unique_lock<mutex>& m,boost::xtime const& wait_until,predicate_type pred)
{
return do_wait(m,system_time(wait_until),pred);
}
template<typename duration_type,typename predicate_type>
bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration,predicate_type pred)
{
return do_wait(m,wait_duration.total_milliseconds(),pred);
while (!pred())
{
if(!timed_wait(m, wait_until))
return false;
}
return true;
}
};
@@ -310,7 +272,7 @@ namespace boost
template<typename lock_type>
void wait(lock_type& m)
{
do_wait(m,detail::timeout::sentinel());
do_wait(m,::boost::detail::get_system_time_sentinel());
}
template<typename lock_type,typename predicate_type>
@@ -325,34 +287,15 @@ namespace boost
return do_wait(m,wait_until);
}
template<typename lock_type>
bool timed_wait(lock_type& m,boost::xtime const& wait_until)
{
return do_wait(m,system_time(wait_until));
}
template<typename lock_type,typename duration_type>
bool timed_wait(lock_type& m,duration_type const& wait_duration)
{
return do_wait(m,wait_duration.total_milliseconds());
}
template<typename lock_type,typename predicate_type>
bool timed_wait(lock_type& m,boost::system_time const& wait_until,predicate_type pred)
{
return do_wait(m,wait_until,pred);
}
template<typename lock_type,typename predicate_type>
bool timed_wait(lock_type& m,boost::xtime const& wait_until,predicate_type pred)
{
return do_wait(m,system_time(wait_until),pred);
}
template<typename lock_type,typename duration_type,typename predicate_type>
bool timed_wait(lock_type& m,duration_type const& wait_duration,predicate_type pred)
{
return do_wait(m,wait_duration.total_milliseconds(),pred);
while (!pred())
{
if(!timed_wait(m, wait_until))
return false;
}
return true;
}
};

View File

@@ -94,9 +94,9 @@ namespace boost
detail::int_to_string(win32::GetCurrentProcessId(), mutex_name + once_mutex_name_fixed_length + sizeof(void*)*2);
#ifdef BOOST_NO_ANSI_APIS
return win32::CreateMutexW(0, 0, mutex_name);
return win32::CreateMutexW(NULL, 0, mutex_name);
#else
return win32::CreateMutexA(0, 0, mutex_name);
return win32::CreateMutexA(NULL, 0, mutex_name);
#endif
}

View File

@@ -48,21 +48,21 @@ namespace boost
}
state_data state;
detail::win32::handle semaphores[2];
detail::win32::handle &unlock_sem;
detail::win32::handle &exclusive_sem;
detail::win32::handle upgrade_sem;
void* semaphores[2];
void* &unlock_sem;
void* &exclusive_sem;
void* upgrade_sem;
void release_waiters(state_data old_state)
{
if(old_state.exclusive_waiting)
{
BOOST_VERIFY(detail::win32::ReleaseSemaphore(exclusive_sem,1,0)!=0);
BOOST_VERIFY(detail::win32::ReleaseSemaphore(exclusive_sem,1,NULL)!=0);
}
if(old_state.shared_waiting || old_state.exclusive_waiting)
{
BOOST_VERIFY(detail::win32::ReleaseSemaphore(unlock_sem,old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0);
BOOST_VERIFY(detail::win32::ReleaseSemaphore(unlock_sem,old_state.shared_waiting + (old_state.exclusive_waiting?1:0),NULL)!=0);
}
}
@@ -215,7 +215,7 @@ namespace boost
{
if(old_state.upgrade)
{
BOOST_VERIFY(detail::win32::ReleaseSemaphore(upgrade_sem,1,0)!=0);
BOOST_VERIFY(detail::win32::ReleaseSemaphore(upgrade_sem,1,NULL)!=0);
}
else
{

View File

@@ -15,11 +15,9 @@
#include "thread_primitives.hpp"
#include "thread_heap_alloc.hpp"
#include <boost/utility.hpp>
#include <boost/assert.hpp>
#include <list>
#include <algorithm>
#include <boost/ref.hpp>
#include <boost/cstdint.hpp>
namespace boost
{
@@ -29,7 +27,6 @@ namespace boost
namespace detail
{
struct thread_exit_callback_node;
struct tss_data_node;
struct thread_data_base
{
@@ -37,14 +34,13 @@ namespace boost
detail::win32::handle_manager thread_handle;
detail::win32::handle_manager interruption_handle;
boost::detail::thread_exit_callback_node* thread_exit_callbacks;
boost::detail::tss_data_node* tss_data;
bool interruption_enabled;
unsigned id;
thread_data_base():
count(0),thread_handle(detail::win32::invalid_handle_value),
interruption_handle(create_anonymous_event(detail::win32::manual_reset_event,detail::win32::event_initially_reset)),
thread_exit_callbacks(0),tss_data(0),
thread_exit_callbacks(0),
interruption_enabled(true),
id(0)
{}
@@ -64,92 +60,8 @@ namespace boost
}
}
void interrupt()
{
BOOST_VERIFY(detail::win32::SetEvent(interruption_handle)!=0);
}
virtual void run()=0;
};
typedef boost::intrusive_ptr<detail::thread_data_base> thread_data_ptr;
struct timeout
{
unsigned long start;
uintmax_t milliseconds;
bool relative;
boost::system_time abs_time;
static unsigned long const max_non_infinite_wait=0xfffffffe;
timeout(uintmax_t milliseconds_):
start(win32::GetTickCount()),
milliseconds(milliseconds_),
relative(true),
abs_time(boost::get_system_time())
{}
timeout(boost::system_time const& abs_time_):
start(win32::GetTickCount()),
milliseconds(0),
relative(false),
abs_time(abs_time_)
{}
struct remaining_time
{
bool more;
unsigned long milliseconds;
remaining_time(uintmax_t remaining):
more(remaining>max_non_infinite_wait),
milliseconds(more?max_non_infinite_wait:(unsigned long)remaining)
{}
};
remaining_time remaining_milliseconds() const
{
if(is_sentinel())
{
return remaining_time(win32::infinite);
}
else if(relative)
{
unsigned long const now=win32::GetTickCount();
unsigned long const elapsed=now-start;
return remaining_time((elapsed<milliseconds)?(milliseconds-elapsed):0);
}
else
{
system_time const now=get_system_time();
if(abs_time<=now)
{
return remaining_time(0);
}
return remaining_time((abs_time-now).total_milliseconds()+1);
}
}
bool is_sentinel() const
{
return milliseconds==~uintmax_t(0);
}
static timeout sentinel()
{
return timeout(sentinel_type());
}
private:
struct sentinel_type
{};
explicit timeout(sentinel_type):
start(0),milliseconds(~uintmax_t(0)),relative(true)
{}
};
}
class BOOST_THREAD_DECL thread
@@ -169,7 +81,7 @@ namespace boost
thread_data(F f_):
f(f_)
{}
thread_data(detail::thread_move_t<F> f_):
thread_data(boost::move_t<F> f_):
f(f_)
{}
@@ -180,15 +92,15 @@ namespace boost
};
mutable boost::mutex thread_info_mutex;
detail::thread_data_ptr thread_info;
boost::intrusive_ptr<detail::thread_data_base> thread_info;
static unsigned __stdcall thread_start_function(void* param);
void start_thread();
explicit thread(detail::thread_data_ptr data);
explicit thread(boost::intrusive_ptr<detail::thread_data_base> data);
detail::thread_data_ptr get_thread_info() const;
boost::intrusive_ptr<detail::thread_data_base> get_thread_info() const;
public:
thread();
~thread();
@@ -200,16 +112,16 @@ namespace boost
start_thread();
}
template <class F>
thread(detail::thread_move_t<F> f):
explicit thread(boost::move_t<F> f):
thread_info(detail::heap_new<thread_data<F> >(f))
{
start_thread();
}
thread(detail::thread_move_t<thread> x);
thread& operator=(detail::thread_move_t<thread> x);
operator detail::thread_move_t<thread>();
detail::thread_move_t<thread> move();
thread(boost::move_t<thread> x);
thread& operator=(boost::move_t<thread> x);
operator boost::move_t<thread>();
boost::move_t<thread> move();
void swap(thread& x);
@@ -241,19 +153,13 @@ namespace boost
static void sleep(const system_time& xt);
// extensions
class interruption_handle;
interruption_handle get_interruption_handle() const;
void interrupt();
bool interruption_requested() const;
};
inline detail::thread_move_t<thread> move(thread& x)
{
return x.move();
}
inline detail::thread_move_t<thread> move(detail::thread_move_t<thread> x)
{
return x;
}
static thread self();
};
template<typename F>
struct thread::thread_data<boost::reference_wrapper<F> >:
@@ -297,7 +203,7 @@ namespace boost
thread::id BOOST_THREAD_DECL get_id();
bool BOOST_THREAD_DECL interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time);
bool BOOST_THREAD_DECL interruptible_wait(detail::win32::handle handle_to_wait_for,unsigned long milliseconds);
inline bool interruptible_wait(unsigned long milliseconds)
{
return interruptible_wait(detail::win32::invalid_handle_value,milliseconds);
@@ -306,6 +212,7 @@ namespace boost
void BOOST_THREAD_DECL interruption_point();
bool BOOST_THREAD_DECL interruption_enabled();
bool BOOST_THREAD_DECL interruption_requested();
thread::interruption_handle BOOST_THREAD_DECL get_interruption_handle();
void BOOST_THREAD_DECL yield();
template<typename TimeDuration>
@@ -318,70 +225,54 @@ namespace boost
class thread::id
{
private:
detail::thread_data_ptr thread_data;
unsigned thread_id;
id(detail::thread_data_ptr thread_data_):
thread_data(thread_data_)
id(unsigned thread_id_):
thread_id(thread_id_)
{}
friend class thread;
friend id this_thread::get_id();
public:
id():
thread_data(0)
thread_id(0)
{}
bool operator==(const id& y) const
{
return thread_data==y.thread_data;
return thread_id==y.thread_id;
}
bool operator!=(const id& y) const
{
return thread_data!=y.thread_data;
return thread_id!=y.thread_id;
}
bool operator<(const id& y) const
{
return thread_data<y.thread_data;
return thread_id<y.thread_id;
}
bool operator>(const id& y) const
{
return y.thread_data<thread_data;
return thread_id>y.thread_id;
}
bool operator<=(const id& y) const
{
return !(y.thread_data<thread_data);
return thread_id<=y.thread_id;
}
bool operator>=(const id& y) const
{
return !(thread_data<y.thread_data);
return thread_id>=y.thread_id;
}
template<class charT, class traits>
friend std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, const id& x)
{
if(x.thread_data)
{
return os<<x.thread_data;
}
else
{
return os<<"{Not-any-thread}";
}
return os<<x.thread_id;
}
void interrupt()
{
if(thread_data)
{
thread_data->interrupt();
}
}
};
inline bool thread::operator==(const thread& other) const
@@ -393,6 +284,56 @@ namespace boost
{
return get_id()!=other.get_id();
}
class thread::interruption_handle
{
private:
boost::detail::win32::handle_manager handle;
friend class thread;
friend interruption_handle this_thread::get_interruption_handle();
interruption_handle(detail::win32::handle h_):
handle(h_)
{}
public:
interruption_handle(interruption_handle const& other):
handle(other.handle.duplicate())
{}
interruption_handle():
handle(0)
{}
void swap(interruption_handle& other)
{
handle.swap(other.handle);
}
interruption_handle& operator=(interruption_handle const& other)
{
interruption_handle temp(other);
swap(temp);
return *this;
}
void reset()
{
handle=0;
}
void interrupt()
{
if(handle)
{
detail::win32::SetEvent(handle);
}
}
typedef void(interruption_handle::*bool_type)();
operator bool_type() const
{
return handle?&interruption_handle::interrupt:0;
}
};
namespace detail
{
@@ -486,18 +427,6 @@ namespace boost
}
}
void interrupt_all()
{
boost::lock_guard<mutex> guard(m);
for(std::list<thread*>::iterator it=threads.begin(),end=threads.end();
it!=end;
++it)
{
(*it)->interrupt();
}
}
int size() const
{
boost::lock_guard<mutex> guard(m);

View File

@@ -6,8 +6,6 @@
#define THREAD_HEAP_ALLOC_HPP
#include <new>
#include "thread_primitives.hpp"
#include <stdexcept>
#include <boost/assert.hpp>
#if defined( BOOST_USE_WINDOWS_H )
# include <windows.h>
@@ -53,116 +51,57 @@ namespace boost
{
namespace detail
{
inline BOOST_THREAD_DECL void* allocate_raw_heap_memory(unsigned size)
{
void* const heap_memory=detail::win32::HeapAlloc(detail::win32::GetProcessHeap(),0,size);
if(!heap_memory)
{
throw std::bad_alloc();
}
return heap_memory;
}
inline BOOST_THREAD_DECL void free_raw_heap_memory(void* heap_memory)
{
BOOST_VERIFY(detail::win32::HeapFree(detail::win32::GetProcessHeap(),0,heap_memory)!=0);
}
template<typename T>
T* heap_new()
{
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
try
{
T* const data=new (heap_memory) T();
return data;
}
catch(...)
{
free_raw_heap_memory(heap_memory);
throw;
}
void* const heap_memory=detail::win32::HeapAlloc(detail::win32::GetProcessHeap(),0,sizeof(T));
T* const data=new (heap_memory) T();
return data;
}
template<typename T,typename A1>
T* heap_new(A1 a1)
{
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
try
{
T* const data=new (heap_memory) T(a1);
return data;
}
catch(...)
{
free_raw_heap_memory(heap_memory);
throw;
}
void* const heap_memory=detail::win32::HeapAlloc(detail::win32::GetProcessHeap(),0,sizeof(T));
T* const data=new (heap_memory) T(a1);
return data;
}
template<typename T,typename A1,typename A2>
T* heap_new(A1 a1,A2 a2)
{
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
try
{
T* const data=new (heap_memory) T(a1,a2);
return data;
}
catch(...)
{
free_raw_heap_memory(heap_memory);
throw;
}
}
template<typename T,typename A1,typename A2,typename A3>
T* heap_new(A1 a1,A2 a2,A3 a3)
{
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
try
{
T* const data=new (heap_memory) T(a1,a2,a3);
return data;
}
catch(...)
{
free_raw_heap_memory(heap_memory);
throw;
}
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
T* heap_new(A1 a1,A2 a2,A3 a3,A4 a4)
{
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
try
{
T* const data=new (heap_memory) T(a1,a2,a3,a4);
return data;
}
catch(...)
{
free_raw_heap_memory(heap_memory);
throw;
}
void* const heap_memory=detail::win32::HeapAlloc(detail::win32::GetProcessHeap(),0,sizeof(T));
T* const data=new (heap_memory) T(a1,a2);
return data;
}
template<typename T>
void heap_delete(T* data)
{
data->~T();
free_raw_heap_memory(data);
detail::win32::HeapFree(detail::win32::GetProcessHeap(),0,data);
}
template<typename T>
struct do_heap_delete
struct do_delete
{
void operator()(T* data) const
T* data;
do_delete(T* data_):
data(data_)
{}
void operator()() const
{
detail::heap_delete(data);
}
};
template<typename T>
do_delete<T> make_heap_deleter(T* data)
{
return do_delete<T>(data);
}
}
}

View File

@@ -53,7 +53,6 @@ namespace boost
using ::SleepEx;
using ::Sleep;
using ::QueueUserAPC;
using ::GetTickCount;
}
}
}
@@ -121,8 +120,6 @@ namespace boost
typedef void (__stdcall *queue_user_apc_callback_function)(ulong_ptr);
__declspec(dllimport) unsigned long __stdcall QueueUserAPC(queue_user_apc_callback_function,void*,ulong_ptr);
__declspec(dllimport) unsigned long __stdcall GetTickCount();
# ifndef UNDER_CE
__declspec(dllimport) unsigned long __stdcall GetCurrentProcessId();
__declspec(dllimport) unsigned long __stdcall GetCurrentThreadId();
@@ -181,9 +178,9 @@ namespace boost
inline handle create_anonymous_semaphore(long initial_count,long max_count)
{
#if !defined(BOOST_NO_ANSI_APIS)
handle const res=CreateSemaphoreA(0,initial_count,max_count,0);
handle const res=CreateSemaphoreA(NULL,initial_count,max_count,NULL);
#else
handle const res=CreateSemaphoreW(0,initial_count,max_count,0);
handle const res=CreateSemaphoreW(NULL,initial_count,max_count,NULL);
#endif
if(!res)
{

View File

@@ -1,103 +0,0 @@
#ifndef BOOST_THREAD_WIN32_TSS_HPP
#define BOOST_THREAD_WIN32_TSS_HPP
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// (C) Copyright 2007 Anthony Williams
#include <boost/shared_ptr.hpp>
#include "thread_heap_alloc.hpp"
namespace boost
{
namespace detail
{
struct tss_cleanup_function
{
virtual ~tss_cleanup_function()
{}
virtual void operator()(void* data)=0;
};
BOOST_THREAD_DECL void set_tss_data(void const* key,boost::shared_ptr<tss_cleanup_function> func,void* tss_data,bool cleanup_existing);
BOOST_THREAD_DECL void* get_tss_data(void const* key);
}
template <typename T>
class thread_specific_ptr
{
private:
thread_specific_ptr(thread_specific_ptr&);
thread_specific_ptr& operator=(thread_specific_ptr&);
struct delete_data:
detail::tss_cleanup_function
{
void operator()(void* data)
{
delete static_cast<T*>(data);
}
};
struct run_custom_cleanup_function:
detail::tss_cleanup_function
{
void (*cleanup_function)(T*);
explicit run_custom_cleanup_function(void (*cleanup_function_)(T*)):
cleanup_function(cleanup_function_)
{}
void operator()(void* data)
{
cleanup_function(static_cast<T*>(data));
}
};
boost::shared_ptr<detail::tss_cleanup_function> cleanup;
public:
thread_specific_ptr():
cleanup(detail::heap_new<delete_data>(),detail::do_heap_delete<delete_data>())
{}
explicit thread_specific_ptr(void (*func_)(T*)):
cleanup(detail::heap_new<run_custom_cleanup_function>(func_),detail::do_heap_delete<run_custom_cleanup_function>())
{}
~thread_specific_ptr()
{
reset();
}
T* get() const
{
return static_cast<T*>(detail::get_tss_data(this));
}
T* operator->() const
{
return get();
}
T& operator*() const
{
return *get();
}
T* release()
{
T* const temp=get();
detail::set_tss_data(this,0,0,false);
return temp;
}
void reset(T* new_value=0)
{
T* const current_value=get();
if(current_value!=new_value)
{
detail::set_tss_data(this,cleanup,new_value,true);
}
}
};
}
#endif

View File

@@ -1,6 +1,6 @@
<!-- Copyright (c) 2002-2003 William E. Kempf.
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
-->
<html>

View File

@@ -1,51 +0,0 @@
// Copyright (C) 2007 Anthony Williams
//
// 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)
#define __STDC_CONSTANT_MACROS
#include <boost/thread/once.hpp>
#include <boost/assert.hpp>
#include <pthread.h>
#include <stdlib.h>
namespace boost
{
namespace detail
{
BOOST_THREAD_DECL boost::uintmax_t once_global_epoch=UINTMAX_C(~0);
BOOST_THREAD_DECL pthread_mutex_t once_epoch_mutex=PTHREAD_MUTEX_INITIALIZER;
BOOST_THREAD_DECL pthread_cond_t once_epoch_cv = PTHREAD_COND_INITIALIZER;
namespace
{
pthread_key_t epoch_tss_key;
pthread_once_t epoch_tss_key_flag=PTHREAD_ONCE_INIT;
extern "C" void delete_epoch_tss_data(void* data)
{
free(data);
}
extern "C" void create_epoch_tss_key()
{
BOOST_VERIFY(!pthread_key_create(&epoch_tss_key,delete_epoch_tss_data));
}
}
boost::uintmax_t& get_once_per_thread_epoch()
{
BOOST_VERIFY(!pthread_once(&epoch_tss_key_flag,create_epoch_tss_key));
void* data=pthread_getspecific(epoch_tss_key);
if(!data)
{
data=malloc(sizeof(boost::uintmax_t));
BOOST_VERIFY(!pthread_setspecific(epoch_tss_key,data));
*static_cast<boost::uintmax_t*>(data)=UINTMAX_C(~0);
}
return *static_cast<boost::uintmax_t*>(data);
}
}
}

View File

@@ -12,15 +12,6 @@
#include <boost/thread/condition.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/once.hpp>
#include <boost/thread/tss.hpp>
#ifdef __linux__
#include <sys/sysinfo.h>
#elif defined(__APPLE__) || defined(__FreeBSD__)
#include <sys/types.h>
#include <sys/sysctl.h>
#elif defined(__sun)
#include <unistd.h>
#endif
#include "timeconv.inl"
@@ -32,24 +23,6 @@ namespace boost
{
boost::detail::thread_exit_function_base* func;
thread_exit_callback_node* next;
thread_exit_callback_node(boost::detail::thread_exit_function_base* func_,
thread_exit_callback_node* next_):
func(func_),next(next_)
{}
};
struct tss_data_node
{
void const* key;
boost::shared_ptr<boost::detail::tss_cleanup_function> func;
void* value;
tss_data_node* next;
tss_data_node(void const* key_,boost::shared_ptr<boost::detail::tss_cleanup_function> func_,void* value_,
tss_data_node* next_):
key(key_),func(func_),value(value_),next(next_)
{}
};
namespace
@@ -64,31 +37,17 @@ namespace boost
boost::detail::thread_data_base* thread_info=static_cast<boost::detail::thread_data_base*>(data);
if(thread_info)
{
while(thread_info->tss_data || thread_info->thread_exit_callbacks)
while(thread_info->thread_exit_callbacks)
{
while(thread_info->thread_exit_callbacks)
boost::detail::thread_exit_callback_node* const current_node=thread_info->thread_exit_callbacks;
thread_info->thread_exit_callbacks=current_node->next;
if(current_node->func)
{
detail::thread_exit_callback_node* const current_node=thread_info->thread_exit_callbacks;
thread_info->thread_exit_callbacks=current_node->next;
if(current_node->func)
{
(*current_node->func)();
delete current_node->func;
}
delete current_node;
}
while(thread_info->tss_data)
{
detail::tss_data_node* const current_node=thread_info->tss_data;
thread_info->tss_data=current_node->next;
if(current_node->func)
{
(*current_node->func)(current_node->value);
}
delete current_node;
(*current_node->func)();
delete current_node->func;
}
delete current_node;
}
thread_info->self.reset();
}
}
}
@@ -96,7 +55,7 @@ namespace boost
void create_current_thread_tls_key()
{
BOOST_VERIFY(!pthread_key_create(&current_thread_tls_key,&tls_destructor));
BOOST_VERIFY(!pthread_key_create(&current_thread_tls_key,NULL));
}
}
@@ -141,39 +100,8 @@ namespace boost
thread_info->done_condition.notify_all();
return 0;
}
}
struct externally_launched_thread:
detail::thread_data_base
{
externally_launched_thread()
{
interrupt_enabled=false;
}
void run()
{}
};
detail::thread_data_base* make_external_thread_data()
{
detail::thread_data_base* const me(new externally_launched_thread());
me->self.reset(me);
set_current_thread_data(me);
return me;
}
detail::thread_data_base* get_or_make_current_thread_data()
{
detail::thread_data_base* current_thread_data(detail::get_current_thread_data());
if(!current_thread_data)
{
current_thread_data=make_external_thread_data();
}
return current_thread_data;
}
}
@@ -196,37 +124,6 @@ namespace boost
detach();
}
thread::thread(detail::thread_move_t<thread> x)
{
lock_guard<mutex> lock(x->thread_info_mutex);
thread_info=x->thread_info;
x->thread_info.reset();
}
thread& thread::operator=(detail::thread_move_t<thread> x)
{
thread new_thread(x);
swap(new_thread);
return *this;
}
thread::operator detail::thread_move_t<thread>()
{
return move();
}
detail::thread_move_t<thread> thread::move()
{
detail::thread_move_t<thread> x(*this);
return x;
}
void thread::swap(thread& x)
{
thread_info.swap(x.thread_info);
}
bool thread::operator==(const thread& other) const
{
return get_id()==other.get_id();
@@ -237,7 +134,7 @@ namespace boost
return !operator==(other);
}
detail::thread_data_ptr thread::get_thread_info() const
boost::shared_ptr<detail::thread_data_base> thread::get_thread_info() const
{
lock_guard<mutex> l(thread_info_mutex);
return thread_info;
@@ -245,7 +142,7 @@ namespace boost
void thread::join()
{
detail::thread_data_ptr const local_thread_info=get_thread_info();
boost::shared_ptr<detail::thread_data_base> const local_thread_info=get_thread_info();
if(local_thread_info)
{
bool do_join=false;
@@ -289,7 +186,7 @@ namespace boost
bool thread::timed_join(system_time const& wait_until)
{
detail::thread_data_ptr const local_thread_info=get_thread_info();
boost::shared_ptr<detail::thread_data_base> const local_thread_info=get_thread_info();
if(local_thread_info)
{
bool do_join=false;
@@ -343,7 +240,7 @@ namespace boost
void thread::detach()
{
detail::thread_data_ptr local_thread_info;
boost::shared_ptr<detail::thread_data_base> local_thread_info;
{
lock_guard<mutex> l1(thread_info_mutex);
thread_info.swap(local_thread_info);
@@ -416,28 +313,15 @@ namespace boost
unsigned thread::hardware_concurrency()
{
#if defined(PTW32_VERSION) || defined(__hpux)
return pthread_num_processors_np();
#elif defined(__linux__)
return get_nprocs();
#elif defined(__APPLE__) || defined(__FreeBSD__)
int count;
size_t size=sizeof(count);
return sysctlbyname("hw.ncpu",&count,&size,NULL,0)?0:count;
#elif defined(__sun)
int const count=sysconf(_SC_NPROCESSORS_ONLN);
return (count>0)?count:0;
#else
return 0;
#endif
return 1;
}
thread::id thread::get_id() const
{
detail::thread_data_ptr const local_thread_info=get_thread_info();
boost::shared_ptr<detail::thread_data_base> local_thread_info=get_thread_info();
if(local_thread_info)
{
return id(local_thread_info);
return id(local_thread_info->thread_handle);
}
else
{
@@ -447,7 +331,7 @@ namespace boost
void thread::interrupt()
{
detail::thread_data_ptr const local_thread_info=get_thread_info();
boost::shared_ptr<detail::thread_data_base> local_thread_info=get_thread_info();
if(local_thread_info)
{
lock_guard<mutex> lk(local_thread_info->data_mutex);
@@ -461,7 +345,7 @@ namespace boost
bool thread::interruption_requested() const
{
detail::thread_data_ptr const local_thread_info=get_thread_info();
boost::shared_ptr<detail::thread_data_base> local_thread_info=get_thread_info();
if(local_thread_info)
{
lock_guard<mutex> lk(local_thread_info->data_mutex);
@@ -476,12 +360,6 @@ namespace boost
namespace this_thread
{
thread::id get_id()
{
boost::detail::thread_data_base* const thread_info=get_or_make_current_thread_data();
return thread::id(thread_info?thread_info->shared_from_this():detail::thread_data_ptr());
}
void interruption_point()
{
boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data();
@@ -550,63 +428,6 @@ namespace boost
}
}
namespace detail
{
void add_thread_exit_function(thread_exit_function_base* func)
{
detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
thread_exit_callback_node* const new_node=
new thread_exit_callback_node(func,current_thread_data->thread_exit_callbacks);
current_thread_data->thread_exit_callbacks=new_node;
}
tss_data_node* find_tss_data(void const* key)
{
detail::thread_data_base* const current_thread_data(get_current_thread_data());
if(current_thread_data)
{
detail::tss_data_node* current_node=current_thread_data->tss_data;
while(current_node)
{
if(current_node->key==key)
{
return current_node;
}
current_node=current_node->next;
}
}
return NULL;
}
void* get_tss_data(void const* key)
{
if(tss_data_node* const current_node=find_tss_data(key))
{
return current_node->value;
}
return NULL;
}
void set_tss_data(void const* key,boost::shared_ptr<tss_cleanup_function> func,void* tss_data,bool cleanup_existing)
{
if(tss_data_node* const current_node=find_tss_data(key))
{
if(cleanup_existing && current_node->func)
{
(*current_node->func)(current_node->value);
}
current_node->func=func;
current_node->value=tss_data;
}
else
{
detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
tss_data_node* const new_node=new tss_data_node(key,func,tss_data,current_thread_data->tss_data);
current_thread_data->tss_data=new_node;
}
}
}
thread_group::thread_group()
{
}
@@ -670,19 +491,6 @@ namespace boost
}
}
void thread_group::interrupt_all()
{
boost::lock_guard<mutex> guard(m_mutex);
for(std::list<thread*>::iterator it=m_threads.begin(),end=m_threads.end();
it!=end;
++it)
{
(*it)->interrupt();
}
}
int thread_group::size() const
{
return m_threads.size();

187
src/pthread/tss.cpp Normal file
View File

@@ -0,0 +1,187 @@
// Copyright (C) 2001-2003 William E. Kempf
// Copyright (C) 2006 Roland Schwarz
//
// 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)
#include <boost/thread/detail/config.hpp>
#include <boost/thread/tss.hpp>
#ifndef BOOST_THREAD_NO_TSS_CLEANUP
#include <boost/thread/once.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/exceptions.hpp>
#include <vector>
#include <string>
#include <stdexcept>
#include <cassert>
namespace {
typedef std::vector<void*> tss_slots;
typedef std::vector<boost::function1<void, void*>*> tss_data_cleanup_handlers_type;
boost::once_flag tss_data_once = BOOST_ONCE_INIT;
boost::mutex* tss_data_mutex = 0;
tss_data_cleanup_handlers_type* tss_data_cleanup_handlers = 0;
pthread_key_t tss_data_native_key;
int tss_data_use = 0;
void tss_data_inc_use(boost::mutex::scoped_lock& lk)
{
++tss_data_use;
}
void tss_data_dec_use(boost::mutex::scoped_lock& lk)
{
if (0 == --tss_data_use)
{
tss_data_cleanup_handlers_type::size_type i;
for (i = 0; i < tss_data_cleanup_handlers->size(); ++i)
{
delete (*tss_data_cleanup_handlers)[i];
}
delete tss_data_cleanup_handlers;
tss_data_cleanup_handlers = 0;
lk.unlock();
delete tss_data_mutex;
tss_data_mutex = 0;
pthread_key_delete(tss_data_native_key);
}
}
extern "C" void cleanup_slots(void* p)
{
tss_slots* slots = static_cast<tss_slots*>(p);
boost::mutex::scoped_lock lock(*tss_data_mutex);
for (tss_slots::size_type i = 0; i < slots->size(); ++i)
{
(*(*tss_data_cleanup_handlers)[i])((*slots)[i]);
(*slots)[i] = 0;
}
tss_data_dec_use(lock);
delete slots;
}
void init_tss_data()
{
std::auto_ptr<tss_data_cleanup_handlers_type>
temp(new tss_data_cleanup_handlers_type);
std::auto_ptr<boost::mutex> temp_mutex(new boost::mutex);
if (temp_mutex.get() == 0)
throw boost::thread_resource_error();
int res = pthread_key_create(&tss_data_native_key, &cleanup_slots);
if (res != 0)
return;
// The life time of cleanup handlers and mutex is beeing
// managed by a reference counting technique.
// This avoids a memory leak by releasing the global data
// after last use only, since the execution order of cleanup
// handlers is unspecified on any platform with regards to
// C++ destructor ordering rules.
tss_data_cleanup_handlers = temp.release();
tss_data_mutex = temp_mutex.release();
}
tss_slots* get_slots(bool alloc)
{
tss_slots* slots = 0;
slots = static_cast<tss_slots*>(
pthread_getspecific(tss_data_native_key));
if (slots == 0 && alloc)
{
std::auto_ptr<tss_slots> temp(new tss_slots);
if (pthread_setspecific(tss_data_native_key, temp.get()) != 0)
return 0;
{
boost::mutex::scoped_lock lock(*tss_data_mutex);
tss_data_inc_use(lock);
}
slots = temp.release();
}
return slots;
}
} // namespace
namespace boost {
namespace detail {
void tss::init(boost::function1<void, void*>* pcleanup)
{
boost::call_once(tss_data_once, &init_tss_data);
if (tss_data_cleanup_handlers == 0)
throw thread_resource_error();
boost::mutex::scoped_lock lock(*tss_data_mutex);
try
{
tss_data_cleanup_handlers->push_back(pcleanup);
m_slot = tss_data_cleanup_handlers->size() - 1;
tss_data_inc_use(lock);
}
catch (...)
{
throw thread_resource_error();
}
}
tss::~tss()
{
boost::mutex::scoped_lock lock(*tss_data_mutex);
tss_data_dec_use(lock);
}
void* tss::get() const
{
tss_slots* slots = get_slots(false);
if (!slots)
return 0;
if (m_slot >= slots->size())
return 0;
return (*slots)[m_slot];
}
void tss::set(void* value)
{
tss_slots* slots = get_slots(true);
if (!slots)
throw boost::thread_resource_error();
if (m_slot >= slots->size())
{
try
{
slots->resize(m_slot + 1);
}
catch (...)
{
throw boost::thread_resource_error();
}
}
(*slots)[m_slot] = value;
}
void tss::cleanup(void* value)
{
boost::mutex::scoped_lock lock(*tss_data_mutex);
(*(*tss_data_cleanup_handlers)[m_slot])(value);
}
} // namespace detail
} // namespace boost
#endif //BOOST_THREAD_NO_TSS_CLEANUP

View File

@@ -4,9 +4,6 @@
// (C) Copyright 2007 Anthony Williams
// (C) Copyright 2007 David Deakins
#define _WIN32_WINNT 0x400
#define WINVER 0x400
#include <boost/thread/thread.hpp>
#include <algorithm>
#include <windows.h>
@@ -15,15 +12,34 @@
#endif
#include <stdio.h>
#include <boost/thread/once.hpp>
#include <boost/thread/tss.hpp>
#include <boost/assert.hpp>
#include <boost/thread/detail/tss_hooks.hpp>
#include <boost/date_time/posix_time/conversion.hpp>
namespace boost
{
namespace
{
#if defined(_MSC_VER) && !defined(UNDER_CE)
__declspec(thread) detail::thread_data_base* current_thread_data=0;
detail::thread_data_base* get_current_thread_data()
{
return current_thread_data;
}
void set_current_thread_data(detail::thread_data_base* new_data)
{
current_thread_data=new_data;
}
#elif defined(__BORLANDC__)
detail::thread_data_base* __thread current_thread_data=0;
detail::thread_data_base* get_current_thread_data()
{
return current_thread_data;
}
void set_current_thread_data(detail::thread_data_base* new_data)
{
current_thread_data=new_data;
}
#else
boost::once_flag current_thread_tls_init_flag=BOOST_ONCE_INIT;
DWORD current_thread_tls_key=0;
@@ -44,6 +60,7 @@ namespace boost
boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key);
BOOST_VERIFY(TlsSetValue(current_thread_tls_key,new_data));
}
#endif
#ifdef BOOST_NO_THREADEX
// Windows CE doesn't define _beginthreadex
@@ -67,11 +84,11 @@ namespace boost
typedef void* uintptr_t;
inline uintptr_t const _beginthreadex(void* security, unsigned stack_size, unsigned (__stdcall* start_address)(void*),
void* arglist, unsigned initflag, unsigned* thrdaddr)
void* arglist, unsigned initflag, unsigned* thrdaddr)
{
DWORD threadID;
HANDLE hthread=CreateThread(static_cast<LPSECURITY_ATTRIBUTES>(security),stack_size,ThreadProxy,
new ThreadProxyData(start_address,arglist),initflag,&threadID);
new ThreadProxyData(start_address,arglist),initflag,&threadID);
if (hthread!=0)
*thrdaddr=threadID;
return reinterpret_cast<uintptr_t const>(hthread);
@@ -113,53 +130,26 @@ namespace boost
{}
};
struct tss_data_node
{
void const* key;
boost::shared_ptr<boost::detail::tss_cleanup_function> func;
void* value;
tss_data_node* next;
tss_data_node(void const* key_,boost::shared_ptr<boost::detail::tss_cleanup_function> func_,void* value_,
tss_data_node* next_):
key(key_),func(func_),value(value_),next(next_)
{}
};
}
namespace
{
void run_thread_exit_callbacks()
{
detail::thread_data_ptr current_thread_data(get_current_thread_data(),false);
boost::intrusive_ptr<detail::thread_data_base> current_thread_data(get_current_thread_data(),false);
if(current_thread_data)
{
while(current_thread_data->tss_data || current_thread_data->thread_exit_callbacks)
while(current_thread_data->thread_exit_callbacks)
{
while(current_thread_data->thread_exit_callbacks)
detail::thread_exit_callback_node* const current_node=current_thread_data->thread_exit_callbacks;
current_thread_data->thread_exit_callbacks=current_node->next;
if(current_node->func)
{
detail::thread_exit_callback_node* const current_node=current_thread_data->thread_exit_callbacks;
current_thread_data->thread_exit_callbacks=current_node->next;
if(current_node->func)
{
(*current_node->func)();
boost::detail::heap_delete(current_node->func);
}
boost::detail::heap_delete(current_node);
}
while(current_thread_data->tss_data)
{
detail::tss_data_node* const current_node=current_thread_data->tss_data;
current_thread_data->tss_data=current_node->next;
if(current_node->func)
{
(*current_node->func)(current_node->value);
}
boost::detail::heap_delete(current_node);
(*current_node->func)();
boost::detail::heap_delete(current_node->func);
}
boost::detail::heap_delete(current_node);
}
}
set_current_thread_data(0);
}
@@ -201,7 +191,7 @@ namespace boost
ResumeThread(thread_info->thread_handle);
}
thread::thread(detail::thread_data_ptr data):
thread::thread(boost::intrusive_ptr<detail::thread_data_base> data):
thread_info(data)
{}
@@ -214,58 +204,53 @@ namespace boost
{
++count;
interruption_enabled=false;
thread_handle=detail::win32::duplicate_handle(detail::win32::GetCurrentThread());
}
void run()
{}
};
}
void make_external_thread_data()
thread thread::self()
{
if(!get_current_thread_data())
{
externally_launched_thread* me=detail::heap_new<externally_launched_thread>();
set_current_thread_data(me);
}
detail::thread_data_base* get_or_make_current_thread_data()
{
detail::thread_data_base* current_thread_data(get_current_thread_data());
if(!current_thread_data)
{
make_external_thread_data();
current_thread_data=get_current_thread_data();
}
return current_thread_data;
}
return thread(boost::intrusive_ptr<detail::thread_data_base>(get_current_thread_data()));
}
thread::~thread()
{
detach();
}
thread::thread(detail::thread_move_t<thread> x)
thread::thread(boost::move_t<thread> x)
{
lock_guard<mutex> lock(x->thread_info_mutex);
thread_info=x->thread_info;
x->thread_info=0;
{
boost::mutex::scoped_lock l(x->thread_info_mutex);
thread_info=x->thread_info;
}
x->release_handle();
}
thread& thread::operator=(detail::thread_move_t<thread> x)
thread& thread::operator=(boost::move_t<thread> x)
{
thread new_thread(x);
swap(new_thread);
return *this;
}
thread::operator detail::thread_move_t<thread>()
thread::operator boost::move_t<thread>()
{
return move();
}
detail::thread_move_t<thread> thread::move()
boost::move_t<thread> thread::move()
{
detail::thread_move_t<thread> x(*this);
boost::move_t<thread> x(*this);
return x;
}
@@ -276,9 +261,16 @@ namespace boost
thread::id thread::get_id() const
{
return thread::id(get_thread_info());
boost::intrusive_ptr<detail::thread_data_base> local_thread_info=get_thread_info();
return local_thread_info?thread::id(local_thread_info->id):thread::id();
}
thread::interruption_handle thread::get_interruption_handle() const
{
boost::intrusive_ptr<detail::thread_data_base> local_thread_info=get_thread_info();
return local_thread_info?thread::interruption_handle(local_thread_info->interruption_handle.duplicate()):thread::interruption_handle();
}
bool thread::joinable() const
{
return get_thread_info();
@@ -286,17 +278,17 @@ namespace boost
void thread::join()
{
detail::thread_data_ptr local_thread_info=get_thread_info();
boost::intrusive_ptr<detail::thread_data_base> local_thread_info=get_thread_info();
if(local_thread_info)
{
this_thread::interruptible_wait(local_thread_info->thread_handle,detail::timeout::sentinel());
this_thread::interruptible_wait(local_thread_info->thread_handle,detail::win32::infinite);
release_handle();
}
}
bool thread::timed_join(boost::system_time const& wait_until)
{
detail::thread_data_ptr local_thread_info=get_thread_info();
boost::intrusive_ptr<detail::thread_data_base> local_thread_info=get_thread_info();
if(local_thread_info)
{
if(!this_thread::interruptible_wait(local_thread_info->thread_handle,get_milliseconds_until(wait_until)))
@@ -315,22 +307,22 @@ namespace boost
void thread::release_handle()
{
lock_guard<mutex> l1(thread_info_mutex);
boost::mutex::scoped_lock l1(thread_info_mutex);
thread_info=0;
}
void thread::interrupt()
{
detail::thread_data_ptr local_thread_info=get_thread_info();
boost::intrusive_ptr<detail::thread_data_base> local_thread_info=get_thread_info();
if(local_thread_info)
{
local_thread_info->interrupt();
detail::win32::SetEvent(local_thread_info->interruption_handle);
}
}
bool thread::interruption_requested() const
{
detail::thread_data_ptr local_thread_info=get_thread_info();
boost::intrusive_ptr<detail::thread_data_base> local_thread_info=get_thread_info();
return local_thread_info.get() && (detail::win32::WaitForSingleObject(local_thread_info->interruption_handle,0)==0);
}
@@ -343,11 +335,11 @@ namespace boost
thread::native_handle_type thread::native_handle()
{
detail::thread_data_ptr local_thread_info=get_thread_info();
boost::intrusive_ptr<detail::thread_data_base> local_thread_info=get_thread_info();
return local_thread_info?(detail::win32::handle)local_thread_info->thread_handle:detail::win32::invalid_handle_value;
}
detail::thread_data_ptr thread::get_thread_info() const
boost::intrusive_ptr<detail::thread_data_base> thread::get_thread_info() const
{
boost::mutex::scoped_lock l(thread_info_mutex);
return thread_info;
@@ -355,57 +347,18 @@ namespace boost
namespace this_thread
{
namespace
thread::interruption_handle get_interruption_handle()
{
LARGE_INTEGER get_due_time(detail::timeout const& target_time)
{
LARGE_INTEGER due_time={0};
if(target_time.relative)
{
unsigned long const elapsed_milliseconds=GetTickCount()-target_time.start;
LONGLONG const remaining_milliseconds=(target_time.milliseconds-elapsed_milliseconds);
LONGLONG const hundred_nanoseconds_in_one_millisecond=10000;
if(remaining_milliseconds>0)
{
due_time.QuadPart=-(remaining_milliseconds*hundred_nanoseconds_in_one_millisecond);
}
}
else
{
SYSTEMTIME target_system_time={0};
target_system_time.wYear=target_time.abs_time.date().year();
target_system_time.wMonth=target_time.abs_time.date().month();
target_system_time.wDay=target_time.abs_time.date().day();
target_system_time.wHour=(WORD)target_time.abs_time.time_of_day().hours();
target_system_time.wMinute=(WORD)target_time.abs_time.time_of_day().minutes();
target_system_time.wSecond=(WORD)target_time.abs_time.time_of_day().seconds();
if(!SystemTimeToFileTime(&target_system_time,((FILETIME*)&due_time)))
{
due_time.QuadPart=0;
}
else
{
long const hundred_nanoseconds_in_one_second=10000000;
due_time.QuadPart+=target_time.abs_time.time_of_day().fractional_seconds()*(hundred_nanoseconds_in_one_second/target_time.abs_time.time_of_day().ticks_per_second());
}
}
return due_time;
}
return get_current_thread_data()?thread::interruption_handle(get_current_thread_data()->interruption_handle.duplicate()):thread::interruption_handle();
}
bool interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time)
bool interruptible_wait(detail::win32::handle handle_to_wait_for,unsigned long milliseconds)
{
detail::win32::handle handles[3]={0};
detail::win32::handle handles[2]={0};
unsigned handle_count=0;
unsigned wait_handle_index=~0U;
unsigned interruption_index=~0U;
unsigned timeout_index=~0U;
if(handle_to_wait_for!=detail::win32::invalid_handle_value)
{
wait_handle_index=handle_count;
handles[handle_count++]=handle_to_wait_for;
}
if(get_current_thread_data() && get_current_thread_data()->interruption_enabled)
@@ -413,85 +366,30 @@ namespace boost
interruption_index=handle_count;
handles[handle_count++]=get_current_thread_data()->interruption_handle;
}
detail::win32::handle_manager timer_handle;
#ifndef UNDER_CE
unsigned const min_timer_wait_period=20;
if(!target_time.is_sentinel())
{
detail::timeout::remaining_time const time_left=target_time.remaining_milliseconds();
if(time_left.milliseconds > min_timer_wait_period)
{
// for a long-enough timeout, use a waitable timer (which tracks clock changes)
timer_handle=CreateWaitableTimer(NULL,false,NULL);
if(timer_handle!=0)
{
LARGE_INTEGER due_time=get_due_time(target_time);
bool const set_time_succeeded=SetWaitableTimer(timer_handle,&due_time,0,0,0,false)!=0;
if(set_time_succeeded)
{
timeout_index=handle_count;
handles[handle_count++]=timer_handle;
}
}
}
else if(!target_time.relative)
{
// convert short absolute-time timeouts into relative ones, so we don't race against clock changes
target_time=detail::timeout(time_left.milliseconds);
}
}
#endif
bool const using_timer=timeout_index!=~0u;
detail::timeout::remaining_time time_left(0);
do
if(handle_count)
{
if(!using_timer)
unsigned long const notified_index=detail::win32::WaitForMultipleObjects(handle_count,handles,false,milliseconds);
if((handle_to_wait_for!=detail::win32::invalid_handle_value) && !notified_index)
{
time_left=target_time.remaining_milliseconds();
return true;
}
if(handle_count)
else if(notified_index==interruption_index)
{
unsigned long const notified_index=detail::win32::WaitForMultipleObjects(handle_count,handles,false,using_timer?INFINITE:time_left.milliseconds);
if(notified_index<handle_count)
{
if(notified_index==wait_handle_index)
{
return true;
}
else if(notified_index==interruption_index)
{
detail::win32::ResetEvent(get_current_thread_data()->interruption_handle);
throw thread_interrupted();
}
else if(notified_index==timeout_index)
{
return false;
}
}
}
else
{
detail::win32::Sleep(time_left.milliseconds);
}
if(target_time.relative)
{
target_time.milliseconds-=detail::timeout::max_non_infinite_wait;
detail::win32::ResetEvent(get_current_thread_data()->interruption_handle);
throw thread_interrupted();
}
}
while(time_left.more);
else
{
detail::win32::Sleep(milliseconds);
}
return false;
}
thread::id get_id()
{
return thread::id(get_or_make_current_thread_data());
return thread::id(detail::win32::GetCurrentThreadId());
}
void interruption_point()
@@ -552,78 +450,49 @@ namespace boost
}
}
namespace
{
void NTAPI thread_exit_func_callback(HINSTANCE, DWORD, PVOID);
typedef void (NTAPI* tls_callback)(HINSTANCE, DWORD, PVOID);
#ifdef _MSC_VER
extern "C"
{
extern DWORD _tls_used; //the tls directory (located in .rdata segment)
extern tls_callback __xl_a[], __xl_z[]; //tls initializers */
}
#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0
# pragma data_seg(push, old_seg)
#endif
#pragma data_seg(".CRT$XLB")
tls_callback p_thread_callback = thread_exit_func_callback;
#pragma data_seg()
#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0
# pragma data_seg(pop, old_seg)
#endif
#endif
void NTAPI thread_exit_func_callback(HINSTANCE h, DWORD dwReason, PVOID pv)
{
if((dwReason==DLL_THREAD_DETACH) || (dwReason==DLL_PROCESS_DETACH))
{
run_thread_exit_callbacks();
}
}
}
namespace detail
{
void add_thread_exit_function(thread_exit_function_base* func)
{
detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
thread_exit_callback_node* const new_node=
heap_new<thread_exit_callback_node>(func,
current_thread_data->thread_exit_callbacks);
current_thread_data->thread_exit_callbacks=new_node;
}
tss_data_node* find_tss_data(void const* key)
{
detail::thread_data_base* const current_thread_data(get_current_thread_data());
if(current_thread_data)
{
detail::tss_data_node* current_node=current_thread_data->tss_data;
while(current_node)
{
if(current_node->key==key)
{
return current_node;
}
current_node=current_node->next;
}
}
return NULL;
}
void* get_tss_data(void const* key)
{
if(tss_data_node* const current_node=find_tss_data(key))
{
return current_node->value;
}
return NULL;
}
void set_tss_data(void const* key,boost::shared_ptr<tss_cleanup_function> func,void* tss_data,bool cleanup_existing)
{
tss_cleanup_implemented(); // if anyone uses TSS, we need the cleanup linked in
if(tss_data_node* const current_node=find_tss_data(key))
{
if(cleanup_existing && current_node->func.get())
{
(*current_node->func)(current_node->value);
}
current_node->func=func;
current_node->value=tss_data;
}
else
{
detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
tss_data_node* const new_node=heap_new<tss_data_node>(key,func,tss_data,current_thread_data->tss_data);
current_thread_data->tss_data=new_node;
}
get_current_thread_data()->thread_exit_callbacks);
get_current_thread_data()->thread_exit_callbacks=new_node;
}
}
}
extern "C" BOOST_THREAD_DECL void on_process_enter()
{}
extern "C" BOOST_THREAD_DECL void on_thread_enter()
{}
extern "C" BOOST_THREAD_DECL void on_process_exit()
{}
extern "C" BOOST_THREAD_DECL void on_thread_exit()
{
boost::run_thread_exit_callbacks();
}

211
src/win32/tss.cpp Normal file
View File

@@ -0,0 +1,211 @@
// Copyright (C) 2001-2003 William E. Kempf
// Copyright (C) 2006 Roland Schwarz
// Copyright (C) 2007 Anthony Williams
// Copyright (C) 2007 David Deakins
//
// 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)
#include <boost/thread/detail/config.hpp>
#include <boost/thread/tss.hpp>
#ifndef BOOST_THREAD_NO_TSS_CLEANUP
#include <boost/thread/once.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/exceptions.hpp>
#include <vector>
#include <string>
#include <stdexcept>
#include <cassert>
#include <windows.h>
#include <boost/thread/detail/tss_hooks.hpp>
#if defined(UNDER_CE) && !defined(TLS_OUT_OF_INDEXES)
# define TLS_OUT_OF_INDEXES 0xFFFFFFFF
#endif
namespace {
typedef std::vector<void*> tss_slots;
typedef std::vector<boost::function1<void, void*>*> tss_data_cleanup_handlers_type;
boost::once_flag tss_data_once = BOOST_ONCE_INIT;
boost::mutex* tss_data_mutex = 0;
tss_data_cleanup_handlers_type* tss_data_cleanup_handlers = 0;
DWORD tss_data_native_key=TLS_OUT_OF_INDEXES;
int tss_data_use = 0;
void tss_data_inc_use(boost::mutex::scoped_lock& lk)
{
++tss_data_use;
}
void tss_data_dec_use(boost::mutex::scoped_lock& lk)
{
if (0 == --tss_data_use)
{
tss_data_cleanup_handlers_type::size_type i;
for (i = 0; i < tss_data_cleanup_handlers->size(); ++i)
{
delete (*tss_data_cleanup_handlers)[i];
}
delete tss_data_cleanup_handlers;
tss_data_cleanup_handlers = 0;
lk.unlock();
delete tss_data_mutex;
tss_data_mutex = 0;
TlsFree(tss_data_native_key);
tss_data_native_key=TLS_OUT_OF_INDEXES;
}
}
extern "C" void cleanup_slots(void* p)
{
tss_slots* slots = static_cast<tss_slots*>(p);
boost::mutex::scoped_lock lock(*tss_data_mutex);
for (tss_slots::size_type i = 0; i < slots->size(); ++i)
{
(*(*tss_data_cleanup_handlers)[i])((*slots)[i]);
(*slots)[i] = 0;
}
TlsSetValue(tss_data_native_key,0);
tss_data_dec_use(lock);
delete slots;
}
void init_tss_data()
{
std::auto_ptr<tss_data_cleanup_handlers_type>
temp(new tss_data_cleanup_handlers_type);
std::auto_ptr<boost::mutex> temp_mutex(new boost::mutex);
if (temp_mutex.get() == 0)
throw boost::thread_resource_error();
//Force the cleanup implementation library to be linked in
tss_cleanup_implemented();
//Allocate tls slot
tss_data_native_key = TlsAlloc();
if (tss_data_native_key == TLS_OUT_OF_INDEXES)
return;
// The life time of cleanup handlers and mutex is beeing
// managed by a reference counting technique.
// This avoids a memory leak by releasing the global data
// after last use only, since the execution order of cleanup
// handlers is unspecified on any platform with regards to
// C++ destructor ordering rules.
tss_data_cleanup_handlers = temp.release();
tss_data_mutex = temp_mutex.release();
}
tss_slots* get_slots(bool alloc);
void __cdecl tss_thread_exit()
{
tss_slots* slots = get_slots(false);
if (slots)
cleanup_slots(slots);
}
tss_slots* get_slots(bool alloc)
{
tss_slots* slots = 0;
slots = static_cast<tss_slots*>(
TlsGetValue(tss_data_native_key));
if (slots == 0 && alloc)
{
std::auto_ptr<tss_slots> temp(new tss_slots);
if (at_thread_exit(&tss_thread_exit) == -1)
return 0;
if (!TlsSetValue(tss_data_native_key, temp.get()))
return 0;
{
boost::mutex::scoped_lock lock(*tss_data_mutex);
tss_data_inc_use(lock);
}
slots = temp.release();
}
return slots;
}
} // namespace
namespace boost {
namespace detail {
void tss::init(boost::function1<void, void*>* pcleanup)
{
boost::call_once(tss_data_once, &init_tss_data);
if (tss_data_cleanup_handlers == 0)
throw thread_resource_error();
boost::mutex::scoped_lock lock(*tss_data_mutex);
try
{
tss_data_cleanup_handlers->push_back(pcleanup);
m_slot = tss_data_cleanup_handlers->size() - 1;
tss_data_inc_use(lock);
}
catch (...)
{
throw thread_resource_error();
}
}
tss::~tss()
{
boost::mutex::scoped_lock lock(*tss_data_mutex);
tss_data_dec_use(lock);
}
void* tss::get() const
{
tss_slots* slots = get_slots(false);
if (!slots)
return 0;
if (m_slot >= slots->size())
return 0;
return (*slots)[m_slot];
}
void tss::set(void* value)
{
tss_slots* slots = get_slots(true);
if (!slots)
throw boost::thread_resource_error();
if (m_slot >= slots->size())
{
try
{
slots->resize(m_slot + 1);
}
catch (...)
{
throw boost::thread_resource_error();
}
}
(*slots)[m_slot] = value;
}
void tss::cleanup(void* value)
{
boost::mutex::scoped_lock lock(*tss_data_mutex);
(*(*tss_data_cleanup_handlers)[m_slot])(value);
}
} // namespace detail
} // namespace boost
#endif //BOOST_THREAD_NO_TSS_CLEANUP

218
src/win32/tss_hooks.cpp Normal file
View File

@@ -0,0 +1,218 @@
// Copyright (C) 2004 Michael Glassford
// Copyright (C) 2006 Roland Schwarz
// Copyright (C) 2007 Anthony Williams
// Copyright (C) 2007 David Deakins
// 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)
#include <boost/thread/detail/config.hpp>
#if defined(BOOST_HAS_WINTHREADS)
#include <boost/thread/detail/tss_hooks.hpp>
#include <boost/assert.hpp>
// #include <boost/thread/mutex.hpp>
#include <boost/thread/once.hpp>
#include <list>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
# if defined(UNDER_CE) && !defined(TLS_OUT_OF_INDEXES)
# define TLS_OUT_OF_INDEXES 0xFFFFFFFF
# endif
namespace
{
class CScopedCSLock
{
public:
CScopedCSLock(LPCRITICAL_SECTION cs) : lk(true), cs(cs) {
::EnterCriticalSection(cs);
}
~CScopedCSLock() {
if (lk) ::LeaveCriticalSection(cs);
}
void Unlock() {
lk = false;
::LeaveCriticalSection(cs);
}
private:
bool lk;
LPCRITICAL_SECTION cs;
};
typedef std::list<thread_exit_handler> thread_exit_handlers;
boost::once_flag once_init_threadmon_mutex = BOOST_ONCE_INIT;
//boost::mutex* threadmon_mutex;
// We don't use boost::mutex here, to avoid a memory leak report,
// because we cannot delete it again easily.
CRITICAL_SECTION threadmon_mutex;
void init_threadmon_mutex(void)
{
//threadmon_mutex = new boost::mutex;
//if (!threadmon_mutex)
// throw boost::thread_resource_error();
::InitializeCriticalSection(&threadmon_mutex);
}
const DWORD invalid_tls_key = TLS_OUT_OF_INDEXES;
DWORD tls_key = invalid_tls_key;
unsigned long attached_thread_count = 0;
}
/*
Calls to DllMain() and tls_callback() are serialized by the OS;
however, calls to at_thread_exit are not, so it must be protected
by a mutex. Since we already need a mutex for at_thread_exit(),
and since there is no guarantee that on_process_enter(),
on_process_exit(), on_thread_enter(), and on_thread_exit()
will be called only from DllMain() or tls_callback(), it makes
sense to protect those, too.
*/
extern "C" BOOST_THREAD_DECL int at_thread_exit(
thread_exit_handler exit_handler
)
{
boost::call_once(once_init_threadmon_mutex, init_threadmon_mutex);
//boost::mutex::scoped_lock lock(*threadmon_mutex);
CScopedCSLock lock(&threadmon_mutex);
//Allocate a tls slot if necessary.
if (tls_key == invalid_tls_key)
tls_key = TlsAlloc();
if (tls_key == invalid_tls_key)
return -1;
//Get the exit handlers list for the current thread from tls.
thread_exit_handlers* exit_handlers =
static_cast<thread_exit_handlers*>(TlsGetValue(tls_key));
if (!exit_handlers)
{
//No exit handlers list was created yet.
try
{
//Attempt to create a new exit handlers list.
exit_handlers = new thread_exit_handlers;
if (!exit_handlers)
return -1;
//Attempt to store the list pointer in tls.
if (TlsSetValue(tls_key, exit_handlers))
++attached_thread_count;
else
{
delete exit_handlers;
return -1;
}
}
catch (...)
{
return -1;
}
}
//Like the C runtime library atexit() function,
//functions should be called in the reverse of
//the order they are added, so push them on the
//front of the list.
try
{
exit_handlers->push_front(exit_handler);
}
catch (...)
{
return -1;
}
//Like the atexit() function, a result of zero
//indicates success.
return 0;
}
extern "C" BOOST_THREAD_DECL void on_process_enter(void)
{
boost::call_once(once_init_threadmon_mutex, init_threadmon_mutex);
// boost::mutex::scoped_lock lock(*threadmon_mutex);
CScopedCSLock lock(&threadmon_mutex);
BOOST_ASSERT(attached_thread_count == 0);
}
extern "C" BOOST_THREAD_DECL void on_process_exit(void)
{
boost::call_once(once_init_threadmon_mutex, init_threadmon_mutex);
// boost::mutex::scoped_lock lock(*threadmon_mutex);
CScopedCSLock lock(&threadmon_mutex);
BOOST_ASSERT(attached_thread_count == 0);
//Free the tls slot if one was allocated.
if (tls_key != invalid_tls_key)
{
TlsFree(tls_key);
tls_key = invalid_tls_key;
}
}
extern "C" BOOST_THREAD_DECL void on_thread_enter(void)
{
//boost::call_once(init_threadmon_mutex, once_init_threadmon_mutex);
//boost::mutex::scoped_lock lock(*threadmon_mutex);
}
extern "C" BOOST_THREAD_DECL void on_thread_exit(void)
{
boost::call_once(once_init_threadmon_mutex, init_threadmon_mutex);
// boost::mutex::scoped_lock lock(*threadmon_mutex);
CScopedCSLock lock(&threadmon_mutex);
//Get the exit handlers list for the current thread from tls.
if (tls_key == invalid_tls_key)
return;
thread_exit_handlers* exit_handlers =
static_cast<thread_exit_handlers*>(TlsGetValue(tls_key));
//If a handlers list was found, use it.
if (exit_handlers && TlsSetValue(tls_key, 0))
{
BOOST_ASSERT(attached_thread_count > 0);
--attached_thread_count;
//lock.unlock();
lock.Unlock();
//Call each handler and remove it from the list
while (!exit_handlers->empty())
{
if (thread_exit_handler exit_handler = *exit_handlers->begin())
(*exit_handler)();
exit_handlers->pop_front();
}
delete exit_handlers;
exit_handlers = 0;
}
}
#endif //defined(BOOST_HAS_WINTHREADS)

View File

@@ -1,6 +1,4 @@
// $Id$
// (C) Copyright Aaron W. LaFramboise, Roland Schwarz, Michael Glassford 2004.
// (C) Copyright 2007 Roland Schwarz
// (C) Copyright 2007 Anthony Williams
// (C) Copyright 2007 David Deakins
// Use, modification and distribution are subject to the
@@ -9,75 +7,7 @@
#include <boost/thread/detail/config.hpp>
#if defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_LIB)
#if defined(__MINGW32__) && !defined(_WIN64)
#include <boost/thread/detail/tss_hooks.hpp>
#include <windows.h>
#include <cstdlib>
extern "C" void tss_cleanup_implemented(void) {}
namespace {
void NTAPI on_tls_callback(void* h, DWORD dwReason, PVOID pv)
{
switch (dwReason)
{
case DLL_THREAD_DETACH:
{
on_thread_exit();
break;
}
}
}
void on_after_ctors(void)
{
on_process_enter();
}
void on_before_dtors(void)
{
on_thread_exit();
}
void on_after_dtors(void)
{
on_process_exit();
}
}
extern "C" {
void (* after_ctors )(void) __attribute__((section(".ctors"))) = on_after_ctors;
void (* before_dtors)(void) __attribute__((section(".dtors"))) = on_before_dtors;
void (* after_dtors )(void) __attribute__((section(".dtors.zzz"))) = on_after_dtors;
ULONG __tls_index__ = 0;
char __tls_end__ __attribute__((section(".tls$zzz"))) = 0;
char __tls_start__ __attribute__((section(".tls"))) = 0;
PIMAGE_TLS_CALLBACK __crt_xl_start__ __attribute__ ((section(".CRT$XLA"))) = 0;
PIMAGE_TLS_CALLBACK __crt_xl_tls_callback__ __attribute__ ((section(".CRT$XLB"))) = on_tls_callback;
PIMAGE_TLS_CALLBACK __crt_xl_end__ __attribute__ ((section(".CRT$XLZ"))) = 0;
}
extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata$T"))) =
{
(DWORD) &__tls_start__,
(DWORD) &__tls_end__,
(DWORD) &__tls_index__,
(DWORD) (&__crt_xl_start__+1),
(DWORD) 0,
(DWORD) 0
};
#elif defined(_MSC_VER) && !defined(UNDER_CE)
#if defined(BOOST_THREAD_BUILD_LIB) && defined(_MSC_VER) && !defined(UNDER_CE)
#include <boost/thread/detail/tss_hooks.hpp>
@@ -120,16 +50,6 @@ extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata
//The .CRT$Xxx information is taken from Codeguru:
//http://www.codeguru.com/Cpp/misc/misc/threadsprocesses/article.php/c6945__2/
#if (_MSC_VER >= 1400)
#pragma section(".CRT$XIU",long,read)
#pragma section(".CRT$XCU",long,read)
#pragma section(".CRT$XTU",long,read)
#pragma section(".CRT$XLC",long,read)
static __declspec(allocate(".CRT$XLC")) _TLSCB __xl_ca=on_tls_callback;
static __declspec(allocate(".CRT$XIU"))_PVFV p_tls_prepare = on_tls_prepare;
static __declspec(allocate(".CRT$XCU"))_PVFV p_process_init = on_process_init;
static __declspec(allocate(".CRT$XTU"))_PVFV p_process_term = on_process_term;
#else
#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0
# pragma data_seg(push, old_seg)
#endif
@@ -154,6 +74,7 @@ extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata
#pragma data_seg(".CRT$XLB")
_TLSCB p_thread_callback = on_tls_callback;
#pragma data_seg()
//Callback for termination.
#pragma data_seg(".CRT$XTU")
@@ -162,7 +83,6 @@ extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata
#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0
# pragma data_seg(pop, old_seg)
#endif
#endif
PVAPI on_tls_prepare(void)
{
@@ -257,6 +177,5 @@ extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata
longer needed and can be removed.
*/
}
#endif //defined(_MSC_VER) && !defined(UNDER_CE)
#endif //defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_LIB)

2
test/.cvsignore Normal file
View File

@@ -0,0 +1,2 @@
bin
*.pdb

View File

@@ -1,5 +1,4 @@
# (C) Copyright William E. Kempf 2001.
# (C) Copyright 2007 Anthony Williams.
# 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)
#
@@ -35,21 +34,13 @@ rule thread-run ( sources )
{
test-suite "threads"
: [ thread-run test_thread.cpp ]
[ thread-run test_thread_id.cpp ]
[ thread-run test_hardware_concurrency.cpp ]
[ thread-run test_thread_move.cpp ]
[ thread-run test_move_function.cpp ]
[ thread-run test_mutex.cpp ]
[ thread-run test_condition_notify_one.cpp ]
[ thread-run test_condition_timed_wait_times_out.cpp ]
[ thread-run test_condition_notify_all.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 ]
[ thread-run test_shared_mutex.cpp ]
[ thread-run test_shared_mutex_part_2.cpp ]
[ thread-run test_lock_concept.cpp ]
;
}

View File

@@ -1,95 +0,0 @@
#ifndef CONDITION_TEST_COMMON_HPP
#define CONDITION_TEST_COMMON_HPP
// Copyright (C) 2007 Anthony Williams
//
// 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)
#include <boost/thread/condition_variable.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread_time.hpp>
unsigned const timeout_seconds=5;
struct wait_for_flag
{
boost::mutex mutex;
boost::condition_variable cond_var;
bool flag;
unsigned woken;
wait_for_flag():
flag(false),woken(0)
{}
struct check_flag
{
bool const& flag;
check_flag(bool const& flag_):
flag(flag_)
{}
bool operator()() const
{
return flag;
}
};
void wait_without_predicate()
{
boost::mutex::scoped_lock lock(mutex);
while(!flag)
{
cond_var.wait(lock);
}
++woken;
}
void wait_with_predicate()
{
boost::mutex::scoped_lock lock(mutex);
cond_var.wait(lock,check_flag(flag));
if(flag)
{
++woken;
}
}
void timed_wait_without_predicate()
{
boost::system_time const timeout=boost::get_system_time()+boost::posix_time::seconds(timeout_seconds);
boost::mutex::scoped_lock lock(mutex);
while(!flag)
{
if(!cond_var.timed_wait(lock,timeout))
{
return;
}
}
++woken;
}
void timed_wait_with_predicate()
{
boost::system_time const timeout=boost::get_system_time()+boost::posix_time::seconds(timeout_seconds);
boost::mutex::scoped_lock lock(mutex);
if(cond_var.timed_wait(lock,timeout,check_flag(flag)) && flag)
{
++woken;
}
}
void relative_timed_wait_with_predicate()
{
boost::mutex::scoped_lock lock(mutex);
if(cond_var.timed_wait(lock,boost::posix_time::seconds(timeout_seconds),check_flag(flag)) && flag)
{
++woken;
}
}
};
#endif

View File

@@ -1,62 +0,0 @@
#ifndef SHARED_MUTEX_LOCKING_THREAD_HPP
#define SHARED_MUTEX_LOCKING_THREAD_HPP
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition_variable.hpp>
#include <boost/thread/shared_mutex.hpp>
template<typename lock_type>
class locking_thread
{
boost::shared_mutex& rw_mutex;
unsigned& unblocked_count;
boost::condition_variable& unblocked_condition;
unsigned& simultaneous_running_count;
unsigned& max_simultaneous_running;
boost::mutex& unblocked_count_mutex;
boost::mutex& finish_mutex;
public:
locking_thread(boost::shared_mutex& rw_mutex_,
unsigned& unblocked_count_,
boost::mutex& unblocked_count_mutex_,
boost::condition_variable& unblocked_condition_,
boost::mutex& finish_mutex_,
unsigned& simultaneous_running_count_,
unsigned& max_simultaneous_running_):
rw_mutex(rw_mutex_),
unblocked_count(unblocked_count_),
unblocked_condition(unblocked_condition_),
simultaneous_running_count(simultaneous_running_count_),
max_simultaneous_running(max_simultaneous_running_),
unblocked_count_mutex(unblocked_count_mutex_),
finish_mutex(finish_mutex_)
{}
void operator()()
{
// acquire lock
lock_type lock(rw_mutex);
// increment count to show we're unblocked
{
boost::mutex::scoped_lock ublock(unblocked_count_mutex);
++unblocked_count;
unblocked_condition.notify_one();
++simultaneous_running_count;
if(simultaneous_running_count>max_simultaneous_running)
{
max_simultaneous_running=simultaneous_running_count;
}
}
// wait to finish
boost::mutex::scoped_lock finish_lock(finish_mutex);
{
boost::mutex::scoped_lock ublock(unblocked_count_mutex);
--simultaneous_running_count;
}
}
};
#endif

View File

@@ -10,7 +10,6 @@
#include <boost/thread/barrier.hpp>
#include <boost/test/unit_test.hpp>
#include <vector>
namespace {
@@ -39,20 +38,12 @@ void test_barrier()
boost::thread_group g;
global_parameter = 0;
try
{
for (int i = 0; i < N_THREADS; ++i)
g.create_thread(&barrier_thread);
g.join_all();
}
catch(...)
{
g.interrupt_all();
g.join_all();
throw;
}
BOOST_CHECK_EQUAL(global_parameter,5);
for (int i = 0; i < N_THREADS; ++i)
g.create_thread(&barrier_thread);
g.join_all();
BOOST_CHECK(global_parameter == 5);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])

View File

@@ -1,6 +1,5 @@
// Copyright (C) 2001-2003
// William E. Kempf
// Copyright (C) 2007 Anthony Williams
//
// 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)
@@ -20,7 +19,7 @@ struct condition_test_data
condition_test_data() : notified(0), awoken(0) { }
boost::mutex mutex;
boost::condition_variable condition;
boost::condition condition;
int notified;
int awoken;
};
@@ -83,15 +82,56 @@ void condition_test_waits(condition_test_data* data)
BOOST_CHECK_EQUAL(data->notified, 4);
data->awoken++;
data->condition.notify_one();
}
// Test predicate timed_wait with relative timeout
cond_predicate pred_rel(data->notified, 5);
BOOST_CHECK(data->condition.timed_wait(lock, boost::posix_time::seconds(10), pred_rel));
BOOST_CHECK(lock ? true : false);
BOOST_CHECK(pred_rel());
BOOST_CHECK_EQUAL(data->notified, 5);
data->awoken++;
data->condition.notify_one();
void do_test_condition_notify_one()
{
condition_test_data data;
boost::thread thread(bind(&condition_test_thread, &data));
{
boost::mutex::scoped_lock lock(data.mutex);
BOOST_CHECK(lock ? true : false);
data.notified++;
data.condition.notify_one();
}
thread.join();
BOOST_CHECK_EQUAL(data.awoken, 1);
}
void test_condition_notify_one()
{
timed_test(&do_test_condition_notify_one, 100, execution_monitor::use_mutex);
}
void do_test_condition_notify_all()
{
const int NUMTHREADS = 5;
boost::thread_group threads;
condition_test_data data;
for (int i = 0; i < NUMTHREADS; ++i)
threads.create_thread(bind(&condition_test_thread, &data));
{
boost::mutex::scoped_lock lock(data.mutex);
BOOST_CHECK(lock ? true : false);
data.notified++;
data.condition.notify_all();
}
threads.join_all();
BOOST_CHECK_EQUAL(data.awoken, NUMTHREADS);
}
void test_condition_notify_all()
{
// We should have already tested notify_one here, so
// a timed test with the default execution_monitor::use_condition
// should be OK, and gives the fastest performance
timed_test(&do_test_condition_notify_all, 100);
}
void do_test_condition_waits()
@@ -135,19 +175,10 @@ void do_test_condition_waits()
data.condition.wait(lock);
BOOST_CHECK(lock ? true : false);
BOOST_CHECK_EQUAL(data.awoken, 4);
boost::thread::sleep(delay(1));
data.notified++;
data.condition.notify_one();
while (data.awoken != 5)
data.condition.wait(lock);
BOOST_CHECK(lock ? true : false);
BOOST_CHECK_EQUAL(data.awoken, 5);
}
thread.join();
BOOST_CHECK_EQUAL(data.awoken, 5);
BOOST_CHECK_EQUAL(data.awoken, 4);
}
void test_condition_waits()
@@ -175,11 +206,14 @@ void test_condition_wait_is_a_interruption_point()
timed_test(&do_test_condition_wait_is_a_interruption_point, 1);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: condition test suite");
test->add(BOOST_TEST_CASE(&test_condition_notify_one));
test->add(BOOST_TEST_CASE(&test_condition_notify_all));
test->add(BOOST_TEST_CASE(&test_condition_waits));
test->add(BOOST_TEST_CASE(&test_condition_wait_is_a_interruption_point));

View File

@@ -1,180 +0,0 @@
// Copyright (C) 2007 Anthony Williams
//
// 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)
#include <boost/thread/detail/config.hpp>
#include <boost/thread/thread.hpp>
#include <boost/test/unit_test.hpp>
#include <libs/thread/test/util.inl>
#include "condition_test_common.hpp"
unsigned const number_of_test_threads=5;
void do_test_condition_notify_all_wakes_from_wait()
{
wait_for_flag data;
boost::thread_group group;
try
{
for(unsigned i=0;i<number_of_test_threads;++i)
{
group.create_thread(bind(&wait_for_flag::wait_without_predicate, data));
}
{
boost::mutex::scoped_lock lock(data.mutex);
data.flag=true;
data.cond_var.notify_all();
}
group.join_all();
BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
}
catch(...)
{
group.join_all();
throw;
}
}
void do_test_condition_notify_all_wakes_from_wait_with_predicate()
{
wait_for_flag data;
boost::thread_group group;
try
{
for(unsigned i=0;i<number_of_test_threads;++i)
{
group.create_thread(bind(&wait_for_flag::wait_with_predicate, data));
}
{
boost::mutex::scoped_lock lock(data.mutex);
data.flag=true;
data.cond_var.notify_all();
}
group.join_all();
BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
}
catch(...)
{
group.join_all();
throw;
}
}
void do_test_condition_notify_all_wakes_from_timed_wait()
{
wait_for_flag data;
boost::thread_group group;
try
{
for(unsigned i=0;i<number_of_test_threads;++i)
{
group.create_thread(bind(&wait_for_flag::timed_wait_without_predicate, data));
}
{
boost::mutex::scoped_lock lock(data.mutex);
data.flag=true;
data.cond_var.notify_all();
}
group.join_all();
BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
}
catch(...)
{
group.join_all();
throw;
}
}
void do_test_condition_notify_all_wakes_from_timed_wait_with_predicate()
{
wait_for_flag data;
boost::thread_group group;
try
{
for(unsigned i=0;i<number_of_test_threads;++i)
{
group.create_thread(bind(&wait_for_flag::timed_wait_with_predicate, data));
}
{
boost::mutex::scoped_lock lock(data.mutex);
data.flag=true;
data.cond_var.notify_all();
}
group.join_all();
BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
}
catch(...)
{
group.join_all();
throw;
}
}
void do_test_condition_notify_all_wakes_from_relative_timed_wait_with_predicate()
{
wait_for_flag data;
boost::thread_group group;
try
{
for(unsigned i=0;i<number_of_test_threads;++i)
{
group.create_thread(bind(&wait_for_flag::relative_timed_wait_with_predicate, data));
}
{
boost::mutex::scoped_lock lock(data.mutex);
data.flag=true;
data.cond_var.notify_all();
}
group.join_all();
BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
}
catch(...)
{
group.join_all();
throw;
}
}
void test_condition_notify_all()
{
timed_test(&do_test_condition_notify_all_wakes_from_wait, timeout_seconds);
timed_test(&do_test_condition_notify_all_wakes_from_wait_with_predicate, timeout_seconds);
timed_test(&do_test_condition_notify_all_wakes_from_timed_wait, timeout_seconds);
timed_test(&do_test_condition_notify_all_wakes_from_timed_wait_with_predicate, timeout_seconds);
timed_test(&do_test_condition_notify_all_wakes_from_relative_timed_wait_with_predicate, timeout_seconds);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: condition test suite");
test->add(BOOST_TEST_CASE(&test_condition_notify_all));
return test;
}

View File

@@ -1,113 +0,0 @@
// Copyright (C) 2007 Anthony Williams
//
// 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)
#include <boost/thread/detail/config.hpp>
#include <boost/thread/thread.hpp>
#include <boost/test/unit_test.hpp>
#include <libs/thread/test/util.inl>
#include "condition_test_common.hpp"
void do_test_condition_notify_one_wakes_from_wait()
{
wait_for_flag data;
boost::thread thread(bind(&wait_for_flag::wait_without_predicate, data));
{
boost::mutex::scoped_lock lock(data.mutex);
data.flag=true;
data.cond_var.notify_one();
}
thread.join();
BOOST_CHECK(data.woken);
}
void do_test_condition_notify_one_wakes_from_wait_with_predicate()
{
wait_for_flag data;
boost::thread thread(bind(&wait_for_flag::wait_with_predicate, data));
{
boost::mutex::scoped_lock lock(data.mutex);
data.flag=true;
data.cond_var.notify_one();
}
thread.join();
BOOST_CHECK(data.woken);
}
void do_test_condition_notify_one_wakes_from_timed_wait()
{
wait_for_flag data;
boost::thread thread(bind(&wait_for_flag::timed_wait_without_predicate, data));
{
boost::mutex::scoped_lock lock(data.mutex);
data.flag=true;
data.cond_var.notify_one();
}
thread.join();
BOOST_CHECK(data.woken);
}
void do_test_condition_notify_one_wakes_from_timed_wait_with_predicate()
{
wait_for_flag data;
boost::thread thread(bind(&wait_for_flag::timed_wait_with_predicate, data));
{
boost::mutex::scoped_lock lock(data.mutex);
data.flag=true;
data.cond_var.notify_one();
}
thread.join();
BOOST_CHECK(data.woken);
}
void do_test_condition_notify_one_wakes_from_relative_timed_wait_with_predicate()
{
wait_for_flag data;
boost::thread thread(bind(&wait_for_flag::relative_timed_wait_with_predicate, data));
{
boost::mutex::scoped_lock lock(data.mutex);
data.flag=true;
data.cond_var.notify_one();
}
thread.join();
BOOST_CHECK(data.woken);
}
void test_condition_notify_one()
{
timed_test(&do_test_condition_notify_one_wakes_from_wait, timeout_seconds, execution_monitor::use_mutex);
timed_test(&do_test_condition_notify_one_wakes_from_wait_with_predicate, timeout_seconds, execution_monitor::use_mutex);
timed_test(&do_test_condition_notify_one_wakes_from_timed_wait, timeout_seconds, execution_monitor::use_mutex);
timed_test(&do_test_condition_notify_one_wakes_from_timed_wait_with_predicate, timeout_seconds, execution_monitor::use_mutex);
timed_test(&do_test_condition_notify_one_wakes_from_relative_timed_wait_with_predicate, timeout_seconds, execution_monitor::use_mutex);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: condition test suite");
test->add(BOOST_TEST_CASE(&test_condition_notify_one));
return test;
}

View File

@@ -1,89 +0,0 @@
// Copyright (C) 2007 Anthony Williams
//
// 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)
#include <boost/thread/detail/config.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/thread.hpp>
#include <boost/test/unit_test.hpp>
#include "util.inl"
bool fake_predicate()
{
return false;
}
unsigned const timeout_seconds=5;
unsigned const timeout_grace=1;
boost::posix_time::milliseconds const timeout_resolution(100);
void do_test_timed_wait_times_out()
{
boost::condition_variable cond;
boost::mutex m;
boost::posix_time::seconds const delay(timeout_seconds);
boost::mutex::scoped_lock lock(m);
boost::system_time const start=boost::get_system_time();
boost::system_time const timeout=start+delay;
while(cond.timed_wait(lock,timeout));
boost::system_time const end=boost::get_system_time();
BOOST_CHECK((delay-timeout_resolution)<=(end-start));
}
void do_test_timed_wait_with_predicate_times_out()
{
boost::condition_variable cond;
boost::mutex m;
boost::posix_time::seconds const delay(timeout_seconds);
boost::mutex::scoped_lock lock(m);
boost::system_time const start=boost::get_system_time();
boost::system_time const timeout=start+delay;
bool const res=cond.timed_wait(lock,timeout,fake_predicate);
boost::system_time const end=boost::get_system_time();
BOOST_CHECK(!res);
BOOST_CHECK((delay-timeout_resolution)<=(end-start));
}
void do_test_relative_timed_wait_with_predicate_times_out()
{
boost::condition_variable cond;
boost::mutex m;
boost::posix_time::seconds const delay(timeout_seconds);
boost::mutex::scoped_lock lock(m);
boost::system_time const start=boost::get_system_time();
bool const res=cond.timed_wait(lock,delay,fake_predicate);
boost::system_time const end=boost::get_system_time();
BOOST_CHECK(!res);
BOOST_CHECK((delay-timeout_resolution)<=(end-start));
}
void test_timed_wait_times_out()
{
timed_test(&do_test_timed_wait_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
timed_test(&do_test_timed_wait_with_predicate_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
timed_test(&do_test_relative_timed_wait_with_predicate_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: condition test suite");
test->add(BOOST_TEST_CASE(&test_timed_wait_times_out));
return test;
}

View File

@@ -1,21 +0,0 @@
// Copyright (C) 2007 Anthony Williams
//
// 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)
#include <boost/thread/thread.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/thread/mutex.hpp>
void test_hardware_concurrency_is_non_zero()
{
BOOST_CHECK(boost::thread::hardware_concurrency()!=0);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: hardware concurrency test suite");
test->add(BOOST_TEST_CASE(test_hardware_concurrency_is_non_zero));
return test;
}

View File

@@ -1,54 +0,0 @@
// Copyright (C) 2007 Anthony Williams
//
// 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)
#include <boost/thread/thread.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/thread/mutex.hpp>
void do_nothing()
{}
void test_thread_move_from_lvalue_on_construction()
{
boost::thread src(do_nothing);
boost::thread::id src_id=src.get_id();
boost::thread dest(boost::move(src));
boost::thread::id dest_id=dest.get_id();
BOOST_CHECK(src_id==dest_id);
BOOST_CHECK(src.get_id()==boost::thread::id());
dest.join();
}
void test_thread_move_from_rvalue_on_construction()
{
boost::thread x(boost::move(boost::thread(do_nothing)));
BOOST_CHECK(x.get_id()!=boost::thread::id());
x.join();
}
void test_unique_lock_move_from_lvalue_on_construction()
{
boost::mutex m;
boost::unique_lock<boost::mutex> l(m);
BOOST_CHECK(l.owns_lock());
BOOST_CHECK(l.mutex()==&m);
boost::unique_lock<boost::mutex> l2(boost::move(l));
BOOST_CHECK(!l.owns_lock());
BOOST_CHECK(!l.mutex());
BOOST_CHECK(l2.owns_lock());
BOOST_CHECK(l2.mutex()==&m);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: thread move test suite");
test->add(BOOST_TEST_CASE(test_thread_move_from_lvalue_on_construction));
test->add(BOOST_TEST_CASE(test_thread_move_from_rvalue_on_construction));
test->add(BOOST_TEST_CASE(test_unique_lock_move_from_lvalue_on_construction));
return test;
}

View File

@@ -102,11 +102,6 @@ struct test_timedlock
typedef M mutex_type;
typedef typename M::scoped_timed_lock timed_lock_type;
static bool fake_predicate()
{
return false;
}
void operator()()
{
mutex_type mutex;
@@ -128,17 +123,14 @@ struct test_timedlock
BOOST_CHECK(lock ? true : false);
// Construct and initialize an xtime for a fast time out.
boost::system_time timeout = boost::get_system_time()+boost::posix_time::milliseconds(100);
boost::xtime xt = delay(0, 100);
// Test the lock and the mutex with condition variables.
// No one is going to notify this condition variable. We expect to
// time out.
BOOST_CHECK(!condition.timed_wait(lock, timeout, fake_predicate));
BOOST_CHECK(!condition.timed_wait(lock, xt));
BOOST_CHECK(lock ? true : false);
boost::system_time now=boost::get_system_time();
boost::posix_time::milliseconds const timeout_resolution(20);
BOOST_CHECK((timeout-timeout_resolution)<now);
BOOST_CHECK(in_range(xt));
// Test the lock, unlock and timedlock methods.
lock.unlock();
@@ -150,17 +142,6 @@ struct test_timedlock
boost::system_time target = boost::get_system_time()+boost::posix_time::milliseconds(100);
BOOST_CHECK(lock.timed_lock(target));
BOOST_CHECK(lock ? true : false);
lock.unlock();
BOOST_CHECK(!lock);
BOOST_CHECK(mutex.timed_lock(boost::posix_time::milliseconds(100)));
mutex.unlock();
BOOST_CHECK(lock.timed_lock(boost::posix_time::milliseconds(100)));
BOOST_CHECK(lock ? true : false);
lock.unlock();
BOOST_CHECK(!lock);
}
};

View File

@@ -19,7 +19,6 @@ void initialize_variable()
++var_to_init;
}
void call_once_thread()
{
unsigned const loop_count=100;
@@ -41,22 +40,12 @@ void test_call_once()
{
unsigned const num_threads=20;
boost::thread_group group;
try
for(unsigned i=0;i<num_threads;++i)
{
for(unsigned i=0;i<num_threads;++i)
{
group.create_thread(&call_once_thread);
}
group.join_all();
group.create_thread(&call_once_thread);
}
catch(...)
{
group.interrupt_all();
group.join_all();
throw;
}
group.join_all();
BOOST_CHECK_EQUAL(var_to_init,1);
}
@@ -99,21 +88,11 @@ void test_call_once_arbitrary_functor()
unsigned const num_threads=20;
boost::thread_group group;
try
for(unsigned i=0;i<num_threads;++i)
{
for(unsigned i=0;i<num_threads;++i)
{
group.create_thread(&call_once_with_functor);
}
group.join_all();
group.create_thread(&call_once_with_functor);
}
catch(...)
{
group.interrupt_all();
group.join_all();
throw;
}
group.join_all();
BOOST_CHECK_EQUAL(var_to_init_with_functor,1);
}
@@ -158,21 +137,11 @@ void test_call_once_retried_on_exception()
unsigned const num_threads=20;
boost::thread_group group;
try
for(unsigned i=0;i<num_threads;++i)
{
for(unsigned i=0;i<num_threads;++i)
{
group.create_thread(&call_once_with_exception);
}
group.join_all();
group.create_thread(&call_once_with_exception);
}
catch(...)
{
group.interrupt_all();
group.join_all();
throw;
}
group.join_all();
BOOST_CHECK_EQUAL(throw_before_third_pass::pass_counter,3u);
BOOST_CHECK_EQUAL(exception_counter,2u);
}

View File

@@ -5,9 +5,13 @@
#include <boost/test/unit_test.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition_variable.hpp>
#include <boost/thread/shared_mutex.hpp>
#include <boost/thread/xtime.hpp>
#include "util.inl"
#include "shared_mutex_locking_thread.hpp"
#include <iostream>
#include <boost/date_time/posix_time/posix_time_io.hpp>
#define CHECK_LOCKED_VALUE_EQUAL(mutex_name,value,expected_value) \
{ \
@@ -15,6 +19,65 @@
BOOST_CHECK_EQUAL(value,expected_value); \
}
namespace
{
template<typename lock_type>
class locking_thread
{
boost::shared_mutex& rw_mutex;
unsigned& unblocked_count;
unsigned& simultaneous_running_count;
unsigned& max_simultaneous_running;
boost::mutex& unblocked_count_mutex;
boost::condition_variable& unblocked_condition;
boost::mutex& finish_mutex;
public:
locking_thread(boost::shared_mutex& rw_mutex_,
unsigned& unblocked_count_,
boost::mutex& unblocked_count_mutex_,
boost::condition_variable& unblocked_condition_,
boost::mutex& finish_mutex_,
unsigned& simultaneous_running_count_,
unsigned& max_simultaneous_running_):
rw_mutex(rw_mutex_),
unblocked_count(unblocked_count_),
unblocked_condition(unblocked_condition_),
simultaneous_running_count(simultaneous_running_count_),
max_simultaneous_running(max_simultaneous_running_),
unblocked_count_mutex(unblocked_count_mutex_),
finish_mutex(finish_mutex_)
{}
void operator()()
{
// acquire lock
lock_type lock(rw_mutex);
// increment count to show we're unblocked
{
boost::mutex::scoped_lock ublock(unblocked_count_mutex);
++unblocked_count;
unblocked_condition.notify_one();
++simultaneous_running_count;
if(simultaneous_running_count>max_simultaneous_running)
{
max_simultaneous_running=simultaneous_running_count;
}
}
// wait to finish
boost::mutex::scoped_lock finish_lock(finish_mutex);
{
boost::mutex::scoped_lock ublock(unblocked_count_mutex);
--simultaneous_running_count;
}
}
};
}
void test_multiple_readers()
{
unsigned const number_of_threads=100;
@@ -29,36 +92,27 @@ void test_multiple_readers()
boost::condition_variable unblocked_condition;
boost::mutex finish_mutex;
boost::mutex::scoped_lock finish_lock(finish_mutex);
try
for(unsigned i=0;i<number_of_threads;++i)
{
for(unsigned i=0;i<number_of_threads;++i)
{
pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
finish_mutex,simultaneous_running_count,max_simultaneous_running));
}
{
boost::mutex::scoped_lock lk(unblocked_count_mutex);
while(unblocked_count<number_of_threads)
{
unblocked_condition.wait(lk);
}
}
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,number_of_threads);
finish_lock.unlock();
pool.join_all();
pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
finish_mutex,simultaneous_running_count,max_simultaneous_running));
}
catch(...)
{
pool.interrupt_all();
pool.join_all();
throw;
boost::mutex::scoped_lock lk(unblocked_count_mutex);
while(unblocked_count<number_of_threads)
{
unblocked_condition.wait(lk);
}
}
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,number_of_threads);
finish_lock.unlock();
pool.join_all();
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,number_of_threads);
}
@@ -77,29 +131,20 @@ void test_only_one_writer_permitted()
boost::mutex finish_mutex;
boost::mutex::scoped_lock finish_lock(finish_mutex);
try
for(unsigned i=0;i<number_of_threads;++i)
{
for(unsigned i=0;i<number_of_threads;++i)
{
pool.create_thread(locking_thread<boost::unique_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
finish_mutex,simultaneous_running_count,max_simultaneous_running));
}
boost::thread::sleep(delay(2));
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U);
finish_lock.unlock();
pool.join_all();
}
catch(...)
{
pool.interrupt_all();
pool.join_all();
throw;
pool.create_thread(locking_thread<boost::unique_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
finish_mutex,simultaneous_running_count,max_simultaneous_running));
}
boost::thread::sleep(delay(2));
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U);
finish_lock.unlock();
pool.join_all();
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,number_of_threads);
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1u);
}
@@ -117,34 +162,24 @@ void test_reader_blocks_writer()
boost::mutex finish_mutex;
boost::mutex::scoped_lock finish_lock(finish_mutex);
try
pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
finish_mutex,simultaneous_running_count,max_simultaneous_running));
{
pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
finish_mutex,simultaneous_running_count,max_simultaneous_running));
boost::mutex::scoped_lock lk(unblocked_count_mutex);
while(unblocked_count<1)
{
boost::mutex::scoped_lock lk(unblocked_count_mutex);
while(unblocked_count<1)
{
unblocked_condition.wait(lk);
}
unblocked_condition.wait(lk);
}
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U);
pool.create_thread(locking_thread<boost::unique_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
finish_mutex,simultaneous_running_count,max_simultaneous_running));
boost::thread::sleep(delay(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U);
finish_lock.unlock();
pool.join_all();
}
catch(...)
{
pool.interrupt_all();
pool.join_all();
throw;
}
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U);
pool.create_thread(locking_thread<boost::unique_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
finish_mutex,simultaneous_running_count,max_simultaneous_running));
boost::thread::sleep(delay(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U);
finish_lock.unlock();
pool.join_all();
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,2U);
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1u);
@@ -166,38 +201,28 @@ void test_unlocking_writer_unblocks_all_readers()
unsigned const reader_count=100;
try
for(unsigned i=0;i<reader_count;++i)
{
for(unsigned i=0;i<reader_count;++i)
{
pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
finish_mutex,simultaneous_running_count,max_simultaneous_running));
}
boost::thread::sleep(delay(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,0U);
pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
finish_mutex,simultaneous_running_count,max_simultaneous_running));
}
boost::thread::sleep(delay(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,0U);
write_lock.unlock();
write_lock.unlock();
{
boost::mutex::scoped_lock lk(unblocked_count_mutex);
while(unblocked_count<reader_count)
{
unblocked_condition.wait(lk);
}
}
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count);
finish_lock.unlock();
pool.join_all();
}
catch(...)
{
pool.interrupt_all();
pool.join_all();
throw;
boost::mutex::scoped_lock lk(unblocked_count_mutex);
while(unblocked_count<reader_count)
{
unblocked_condition.wait(lk);
}
}
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count);
finish_lock.unlock();
pool.join_all();
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,reader_count);
}
@@ -221,55 +246,263 @@ void test_unlocking_last_reader_only_unblocks_one_writer()
unsigned const reader_count=100;
unsigned const writer_count=100;
try
for(unsigned i=0;i<reader_count;++i)
{
for(unsigned i=0;i<reader_count;++i)
{
pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
finish_reading_mutex,simultaneous_running_readers,max_simultaneous_readers));
}
boost::thread::sleep(delay(1));
for(unsigned i=0;i<writer_count;++i)
{
pool.create_thread(locking_thread<boost::unique_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
finish_writing_mutex,simultaneous_running_writers,max_simultaneous_writers));
}
{
boost::mutex::scoped_lock lk(unblocked_count_mutex);
while(unblocked_count<reader_count)
{
unblocked_condition.wait(lk);
}
}
boost::thread::sleep(delay(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count);
finish_reading_lock.unlock();
{
boost::mutex::scoped_lock lk(unblocked_count_mutex);
while(unblocked_count<(reader_count+1))
{
unblocked_condition.wait(lk);
}
}
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1);
finish_writing_lock.unlock();
pool.join_all();
pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
finish_reading_mutex,simultaneous_running_readers,max_simultaneous_readers));
}
catch(...)
boost::thread::sleep(delay(1));
for(unsigned i=0;i<writer_count;++i)
{
pool.interrupt_all();
pool.join_all();
throw;
pool.create_thread(locking_thread<boost::unique_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
finish_writing_mutex,simultaneous_running_writers,max_simultaneous_writers));
}
{
boost::mutex::scoped_lock lk(unblocked_count_mutex);
while(unblocked_count<reader_count)
{
unblocked_condition.wait(lk);
}
}
boost::thread::sleep(delay(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count);
finish_reading_lock.unlock();
{
boost::mutex::scoped_lock lk(unblocked_count_mutex);
while(unblocked_count<(reader_count+1))
{
unblocked_condition.wait(lk);
}
}
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1);
finish_writing_lock.unlock();
pool.join_all();
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+writer_count);
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_readers,reader_count);
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_writers,1u);
}
void test_only_one_upgrade_lock_permitted()
{
unsigned const number_of_threads=100;
boost::thread_group pool;
boost::shared_mutex rw_mutex;
unsigned unblocked_count=0;
unsigned simultaneous_running_count=0;
unsigned max_simultaneous_running=0;
boost::mutex unblocked_count_mutex;
boost::condition_variable unblocked_condition;
boost::mutex finish_mutex;
boost::mutex::scoped_lock finish_lock(finish_mutex);
for(unsigned i=0;i<number_of_threads;++i)
{
pool.create_thread(locking_thread<boost::upgrade_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
finish_mutex,simultaneous_running_count,max_simultaneous_running));
}
boost::thread::sleep(delay(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U);
finish_lock.unlock();
pool.join_all();
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,number_of_threads);
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1u);
}
void test_can_lock_upgrade_if_currently_locked_shared()
{
boost::thread_group pool;
boost::shared_mutex rw_mutex;
unsigned unblocked_count=0;
unsigned simultaneous_running_count=0;
unsigned max_simultaneous_running=0;
boost::mutex unblocked_count_mutex;
boost::condition_variable unblocked_condition;
boost::mutex finish_mutex;
boost::mutex::scoped_lock finish_lock(finish_mutex);
unsigned const reader_count=100;
for(unsigned i=0;i<reader_count;++i)
{
pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
finish_mutex,simultaneous_running_count,max_simultaneous_running));
}
boost::thread::sleep(delay(1));
pool.create_thread(locking_thread<boost::upgrade_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
finish_mutex,simultaneous_running_count,max_simultaneous_running));
{
boost::mutex::scoped_lock lk(unblocked_count_mutex);
while(unblocked_count<(reader_count+1))
{
unblocked_condition.wait(lk);
}
}
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1);
finish_lock.unlock();
pool.join_all();
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1);
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,reader_count+1);
}
namespace
{
class simple_writing_thread
{
boost::shared_mutex& rwm;
boost::mutex& finish_mutex;
boost::mutex& unblocked_mutex;
unsigned& unblocked_count;
public:
simple_writing_thread(boost::shared_mutex& rwm_,
boost::mutex& finish_mutex_,
boost::mutex& unblocked_mutex_,
unsigned& unblocked_count_):
rwm(rwm_),finish_mutex(finish_mutex_),
unblocked_mutex(unblocked_mutex_),unblocked_count(unblocked_count_)
{}
void operator()()
{
boost::unique_lock<boost::shared_mutex> lk(rwm);
{
boost::mutex::scoped_lock ulk(unblocked_mutex);
++unblocked_count;
}
boost::mutex::scoped_lock flk(finish_mutex);
}
};
}
void test_if_other_thread_has_write_lock_try_lock_shared_returns_false()
{
boost::shared_mutex rw_mutex;
boost::mutex finish_mutex;
boost::mutex unblocked_mutex;
unsigned unblocked_count=0;
boost::mutex::scoped_lock finish_lock(finish_mutex);
boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
boost::thread::sleep(delay(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
bool const try_succeeded=rw_mutex.try_lock_shared();
BOOST_CHECK(!try_succeeded);
if(try_succeeded)
{
rw_mutex.unlock_shared();
}
finish_lock.unlock();
writer.join();
}
void test_if_no_thread_has_lock_try_lock_shared_returns_true()
{
boost::shared_mutex rw_mutex;
bool const try_succeeded=rw_mutex.try_lock_shared();
BOOST_CHECK(try_succeeded);
if(try_succeeded)
{
rw_mutex.unlock_shared();
}
}
namespace
{
class simple_reading_thread
{
boost::shared_mutex& rwm;
boost::mutex& finish_mutex;
boost::mutex& unblocked_mutex;
unsigned& unblocked_count;
public:
simple_reading_thread(boost::shared_mutex& rwm_,
boost::mutex& finish_mutex_,
boost::mutex& unblocked_mutex_,
unsigned& unblocked_count_):
rwm(rwm_),finish_mutex(finish_mutex_),
unblocked_mutex(unblocked_mutex_),unblocked_count(unblocked_count_)
{}
void operator()()
{
boost::shared_lock<boost::shared_mutex> lk(rwm);
{
boost::mutex::scoped_lock ulk(unblocked_mutex);
++unblocked_count;
}
boost::mutex::scoped_lock flk(finish_mutex);
}
};
}
void test_if_other_thread_has_shared_lock_try_lock_shared_returns_true()
{
boost::shared_mutex rw_mutex;
boost::mutex finish_mutex;
boost::mutex unblocked_mutex;
unsigned unblocked_count=0;
boost::mutex::scoped_lock finish_lock(finish_mutex);
boost::thread writer(simple_reading_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
boost::thread::sleep(delay(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
bool const try_succeeded=rw_mutex.try_lock_shared();
BOOST_CHECK(try_succeeded);
if(try_succeeded)
{
rw_mutex.unlock_shared();
}
finish_lock.unlock();
writer.join();
}
void test_timed_lock_shared_times_out_if_write_lock_held()
{
boost::shared_mutex rw_mutex;
boost::mutex finish_mutex;
boost::mutex unblocked_mutex;
unsigned unblocked_count=0;
boost::mutex::scoped_lock finish_lock(finish_mutex);
boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
boost::thread::sleep(delay(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
boost::system_time const start=boost::get_system_time();
boost::system_time const timeout=start+boost::posix_time::milliseconds(2000);
bool const timed_lock_succeeded=rw_mutex.timed_lock_shared(timeout);
BOOST_CHECK(in_range(boost::get_xtime(timeout),1));
BOOST_CHECK(!timed_lock_succeeded);
if(timed_lock_succeeded)
{
rw_mutex.unlock_shared();
}
finish_lock.unlock();
writer.join();
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
@@ -280,6 +513,12 @@ boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
test->add(BOOST_TEST_CASE(&test_reader_blocks_writer));
test->add(BOOST_TEST_CASE(&test_unlocking_writer_unblocks_all_readers));
test->add(BOOST_TEST_CASE(&test_unlocking_last_reader_only_unblocks_one_writer));
test->add(BOOST_TEST_CASE(&test_only_one_upgrade_lock_permitted));
test->add(BOOST_TEST_CASE(&test_can_lock_upgrade_if_currently_locked_shared));
test->add(BOOST_TEST_CASE(&test_if_other_thread_has_write_lock_try_lock_shared_returns_false));
test->add(BOOST_TEST_CASE(&test_if_no_thread_has_lock_try_lock_shared_returns_true));
test->add(BOOST_TEST_CASE(&test_if_other_thread_has_shared_lock_try_lock_shared_returns_true));
test->add(BOOST_TEST_CASE(&test_timed_lock_shared_times_out_if_write_lock_held));
return test;
}

View File

@@ -1,271 +0,0 @@
// (C) Copyright 2006-7 Anthony Williams
// 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)
#include <boost/test/unit_test.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/xtime.hpp>
#include "util.inl"
#include "shared_mutex_locking_thread.hpp"
#define CHECK_LOCKED_VALUE_EQUAL(mutex_name,value,expected_value) \
{ \
boost::mutex::scoped_lock lock(mutex_name); \
BOOST_CHECK_EQUAL(value,expected_value); \
}
void test_only_one_upgrade_lock_permitted()
{
unsigned const number_of_threads=100;
boost::thread_group pool;
boost::shared_mutex rw_mutex;
unsigned unblocked_count=0;
unsigned simultaneous_running_count=0;
unsigned max_simultaneous_running=0;
boost::mutex unblocked_count_mutex;
boost::condition_variable unblocked_condition;
boost::mutex finish_mutex;
boost::mutex::scoped_lock finish_lock(finish_mutex);
try
{
for(unsigned i=0;i<number_of_threads;++i)
{
pool.create_thread(locking_thread<boost::upgrade_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
finish_mutex,simultaneous_running_count,max_simultaneous_running));
}
boost::thread::sleep(delay(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U);
finish_lock.unlock();
pool.join_all();
}
catch(...)
{
pool.interrupt_all();
pool.join_all();
throw;
}
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,number_of_threads);
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1u);
}
void test_can_lock_upgrade_if_currently_locked_shared()
{
boost::thread_group pool;
boost::shared_mutex rw_mutex;
unsigned unblocked_count=0;
unsigned simultaneous_running_count=0;
unsigned max_simultaneous_running=0;
boost::mutex unblocked_count_mutex;
boost::condition_variable unblocked_condition;
boost::mutex finish_mutex;
boost::mutex::scoped_lock finish_lock(finish_mutex);
unsigned const reader_count=100;
try
{
for(unsigned i=0;i<reader_count;++i)
{
pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
finish_mutex,simultaneous_running_count,max_simultaneous_running));
}
boost::thread::sleep(delay(1));
pool.create_thread(locking_thread<boost::upgrade_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
finish_mutex,simultaneous_running_count,max_simultaneous_running));
{
boost::mutex::scoped_lock lk(unblocked_count_mutex);
while(unblocked_count<(reader_count+1))
{
unblocked_condition.wait(lk);
}
}
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1);
finish_lock.unlock();
pool.join_all();
}
catch(...)
{
pool.interrupt_all();
pool.join_all();
throw;
}
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1);
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,reader_count+1);
}
namespace
{
class simple_writing_thread
{
boost::shared_mutex& rwm;
boost::mutex& finish_mutex;
boost::mutex& unblocked_mutex;
unsigned& unblocked_count;
public:
simple_writing_thread(boost::shared_mutex& rwm_,
boost::mutex& finish_mutex_,
boost::mutex& unblocked_mutex_,
unsigned& unblocked_count_):
rwm(rwm_),finish_mutex(finish_mutex_),
unblocked_mutex(unblocked_mutex_),unblocked_count(unblocked_count_)
{}
void operator()()
{
boost::unique_lock<boost::shared_mutex> lk(rwm);
{
boost::mutex::scoped_lock ulk(unblocked_mutex);
++unblocked_count;
}
boost::mutex::scoped_lock flk(finish_mutex);
}
};
}
void test_if_other_thread_has_write_lock_try_lock_shared_returns_false()
{
boost::shared_mutex rw_mutex;
boost::mutex finish_mutex;
boost::mutex unblocked_mutex;
unsigned unblocked_count=0;
boost::mutex::scoped_lock finish_lock(finish_mutex);
boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
boost::this_thread::sleep(boost::posix_time::seconds(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
bool const try_succeeded=rw_mutex.try_lock_shared();
BOOST_CHECK(!try_succeeded);
if(try_succeeded)
{
rw_mutex.unlock_shared();
}
finish_lock.unlock();
writer.join();
}
void test_if_no_thread_has_lock_try_lock_shared_returns_true()
{
boost::shared_mutex rw_mutex;
bool const try_succeeded=rw_mutex.try_lock_shared();
BOOST_CHECK(try_succeeded);
if(try_succeeded)
{
rw_mutex.unlock_shared();
}
}
namespace
{
class simple_reading_thread
{
boost::shared_mutex& rwm;
boost::mutex& finish_mutex;
boost::mutex& unblocked_mutex;
unsigned& unblocked_count;
public:
simple_reading_thread(boost::shared_mutex& rwm_,
boost::mutex& finish_mutex_,
boost::mutex& unblocked_mutex_,
unsigned& unblocked_count_):
rwm(rwm_),finish_mutex(finish_mutex_),
unblocked_mutex(unblocked_mutex_),unblocked_count(unblocked_count_)
{}
void operator()()
{
boost::shared_lock<boost::shared_mutex> lk(rwm);
{
boost::mutex::scoped_lock ulk(unblocked_mutex);
++unblocked_count;
}
boost::mutex::scoped_lock flk(finish_mutex);
}
};
}
void test_if_other_thread_has_shared_lock_try_lock_shared_returns_true()
{
boost::shared_mutex rw_mutex;
boost::mutex finish_mutex;
boost::mutex unblocked_mutex;
unsigned unblocked_count=0;
boost::mutex::scoped_lock finish_lock(finish_mutex);
boost::thread writer(simple_reading_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
boost::thread::sleep(delay(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
bool const try_succeeded=rw_mutex.try_lock_shared();
BOOST_CHECK(try_succeeded);
if(try_succeeded)
{
rw_mutex.unlock_shared();
}
finish_lock.unlock();
writer.join();
}
void test_timed_lock_shared_times_out_if_write_lock_held()
{
boost::shared_mutex rw_mutex;
boost::mutex finish_mutex;
boost::mutex unblocked_mutex;
unsigned unblocked_count=0;
boost::mutex::scoped_lock finish_lock(finish_mutex);
boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
boost::thread::sleep(delay(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
boost::system_time const start=boost::get_system_time();
boost::system_time const timeout=start+boost::posix_time::milliseconds(2000);
boost::posix_time::milliseconds const timeout_resolution(20);
bool const timed_lock_succeeded=rw_mutex.timed_lock_shared(timeout);
BOOST_CHECK((timeout-timeout_resolution)<boost::get_system_time());
BOOST_CHECK(!timed_lock_succeeded);
if(timed_lock_succeeded)
{
rw_mutex.unlock_shared();
}
finish_lock.unlock();
writer.join();
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: shared_mutex test suite");
test->add(BOOST_TEST_CASE(&test_only_one_upgrade_lock_permitted));
test->add(BOOST_TEST_CASE(&test_can_lock_upgrade_if_currently_locked_shared));
test->add(BOOST_TEST_CASE(&test_if_other_thread_has_write_lock_try_lock_shared_returns_false));
test->add(BOOST_TEST_CASE(&test_if_no_thread_has_lock_try_lock_shared_returns_true));
test->add(BOOST_TEST_CASE(&test_if_other_thread_has_shared_lock_try_lock_shared_returns_true));
test->add(BOOST_TEST_CASE(&test_timed_lock_shared_times_out_if_write_lock_held));
return test;
}

View File

@@ -1,149 +0,0 @@
// Copyright (C) 2007 Anthony Williams
//
// 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)
#include <boost/thread/thread.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/bind.hpp>
void do_nothing()
{}
void test_thread_id_for_default_constructed_thread_is_default_constructed_id()
{
boost::thread t;
BOOST_CHECK(t.get_id()==boost::thread::id());
}
void test_thread_id_for_running_thread_is_not_default_constructed_id()
{
boost::thread t(do_nothing);
BOOST_CHECK(t.get_id()!=boost::thread::id());
t.join();
}
void test_different_threads_have_different_ids()
{
boost::thread t(do_nothing);
boost::thread t2(do_nothing);
BOOST_CHECK(t.get_id()!=t2.get_id());
t.join();
t2.join();
}
void test_thread_ids_have_a_total_order()
{
boost::thread t(do_nothing);
boost::thread t2(do_nothing);
boost::thread t3(do_nothing);
BOOST_CHECK(t.get_id()!=t2.get_id());
BOOST_CHECK(t.get_id()!=t3.get_id());
BOOST_CHECK(t2.get_id()!=t3.get_id());
BOOST_CHECK((t.get_id()<t2.get_id()) != (t2.get_id()<t.get_id()));
BOOST_CHECK((t.get_id()<t3.get_id()) != (t3.get_id()<t.get_id()));
BOOST_CHECK((t2.get_id()<t3.get_id()) != (t3.get_id()<t2.get_id()));
BOOST_CHECK((t.get_id()>t2.get_id()) != (t2.get_id()>t.get_id()));
BOOST_CHECK((t.get_id()>t3.get_id()) != (t3.get_id()>t.get_id()));
BOOST_CHECK((t2.get_id()>t3.get_id()) != (t3.get_id()>t2.get_id()));
BOOST_CHECK((t.get_id()<t2.get_id()) == (t2.get_id()>t.get_id()));
BOOST_CHECK((t2.get_id()<t.get_id()) == (t.get_id()>t2.get_id()));
BOOST_CHECK((t.get_id()<t3.get_id()) == (t3.get_id()>t.get_id()));
BOOST_CHECK((t3.get_id()<t.get_id()) == (t.get_id()>t3.get_id()));
BOOST_CHECK((t2.get_id()<t3.get_id()) == (t3.get_id()>t2.get_id()));
BOOST_CHECK((t3.get_id()<t2.get_id()) == (t2.get_id()>t3.get_id()));
BOOST_CHECK((t.get_id()<t2.get_id()) == (t2.get_id()>=t.get_id()));
BOOST_CHECK((t2.get_id()<t.get_id()) == (t.get_id()>=t2.get_id()));
BOOST_CHECK((t.get_id()<t3.get_id()) == (t3.get_id()>=t.get_id()));
BOOST_CHECK((t3.get_id()<t.get_id()) == (t.get_id()>=t3.get_id()));
BOOST_CHECK((t2.get_id()<t3.get_id()) == (t3.get_id()>=t2.get_id()));
BOOST_CHECK((t3.get_id()<t2.get_id()) == (t2.get_id()>=t3.get_id()));
BOOST_CHECK((t.get_id()<=t2.get_id()) == (t2.get_id()>t.get_id()));
BOOST_CHECK((t2.get_id()<=t.get_id()) == (t.get_id()>t2.get_id()));
BOOST_CHECK((t.get_id()<=t3.get_id()) == (t3.get_id()>t.get_id()));
BOOST_CHECK((t3.get_id()<=t.get_id()) == (t.get_id()>t3.get_id()));
BOOST_CHECK((t2.get_id()<=t3.get_id()) == (t3.get_id()>t2.get_id()));
BOOST_CHECK((t3.get_id()<=t2.get_id()) == (t2.get_id()>t3.get_id()));
if((t.get_id()<t2.get_id()) && (t2.get_id()<t3.get_id()))
{
BOOST_CHECK(t.get_id()<t3.get_id());
}
else if((t.get_id()<t3.get_id()) && (t3.get_id()<t2.get_id()))
{
BOOST_CHECK(t.get_id()<t2.get_id());
}
else if((t2.get_id()<t3.get_id()) && (t3.get_id()<t.get_id()))
{
BOOST_CHECK(t2.get_id()<t.get_id());
}
else if((t2.get_id()<t.get_id()) && (t.get_id()<t3.get_id()))
{
BOOST_CHECK(t2.get_id()<t3.get_id());
}
else if((t3.get_id()<t.get_id()) && (t.get_id()<t2.get_id()))
{
BOOST_CHECK(t3.get_id()<t2.get_id());
}
else if((t3.get_id()<t2.get_id()) && (t2.get_id()<t.get_id()))
{
BOOST_CHECK(t3.get_id()<t.get_id());
}
else
{
BOOST_CHECK(false);
}
boost::thread::id default_id;
BOOST_CHECK(default_id < t.get_id());
BOOST_CHECK(default_id < t2.get_id());
BOOST_CHECK(default_id < t3.get_id());
BOOST_CHECK(default_id <= t.get_id());
BOOST_CHECK(default_id <= t2.get_id());
BOOST_CHECK(default_id <= t3.get_id());
BOOST_CHECK(!(default_id > t.get_id()));
BOOST_CHECK(!(default_id > t2.get_id()));
BOOST_CHECK(!(default_id > t3.get_id()));
BOOST_CHECK(!(default_id >= t.get_id()));
BOOST_CHECK(!(default_id >= t2.get_id()));
BOOST_CHECK(!(default_id >= t3.get_id()));
t.join();
t2.join();
t3.join();
}
void get_thread_id(boost::thread::id* id)
{
*id=boost::this_thread::get_id();
}
void test_thread_id_of_running_thread_returned_by_this_thread_get_id()
{
boost::thread::id id;
boost::thread t(boost::bind(get_thread_id,&id));
boost::thread::id t_id=t.get_id();
t.join();
BOOST_CHECK(id==t_id);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: thread move test suite");
test->add(BOOST_TEST_CASE(test_thread_id_for_default_constructed_thread_is_default_constructed_id));
test->add(BOOST_TEST_CASE(test_thread_id_for_running_thread_is_not_default_constructed_id));
test->add(BOOST_TEST_CASE(test_different_threads_have_different_ids));
test->add(BOOST_TEST_CASE(test_thread_ids_have_a_total_order));
test->add(BOOST_TEST_CASE(test_thread_id_of_running_thread_returned_by_this_thread_get_id));
return test;
}

View File

@@ -1,37 +0,0 @@
// Copyright (C) 2007 Anthony Williams
//
// 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)
#include <boost/thread/thread.hpp>
#include <boost/test/unit_test.hpp>
void do_nothing()
{}
void test_move_on_construction()
{
boost::thread x=boost::thread(do_nothing);
x.join();
}
boost::thread make_thread()
{
return boost::thread(do_nothing);
}
void test_move_from_function_return()
{
boost::thread x=make_thread();
x.join();
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: thread move test suite");
test->add(BOOST_TEST_CASE(test_move_on_construction));
test->add(BOOST_TEST_CASE(test_move_from_function_return));
return test;
}

View File

@@ -1,6 +1,5 @@
// Copyright (C) 2001-2003
// William E. Kempf
// Copyright (C) 2007 Anthony Williams
//
// 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)
@@ -63,7 +62,7 @@ void test_tss_thread()
}
}
#if defined(BOOST_THREAD_PLATFORM_WIN32)
#if defined(BOOST_HAS_WINTHREADS)
typedef HANDLE native_thread_t;
DWORD WINAPI test_tss_thread_native(LPVOID lpParameter)
@@ -74,7 +73,7 @@ void test_tss_thread()
native_thread_t create_native_thread(void)
{
native_thread_t const res=CreateThread(
return CreateThread(
0, //security attributes (0 = not inheritable)
0, //stack size (0 = default)
&test_tss_thread_native, //function to execute
@@ -82,8 +81,6 @@ void test_tss_thread()
0, //creation flags (0 = run immediately)
0 //thread id (0 = thread id not returned)
);
BOOST_CHECK(res!=0);
return res;
}
void join_native_thread(native_thread_t thread)
@@ -94,33 +91,6 @@ void test_tss_thread()
res = CloseHandle(thread);
BOOST_CHECK(SUCCEEDED(res));
}
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
typedef pthread_t native_thread_t;
extern "C"
{
void* test_tss_thread_native(void* lpParameter)
{
test_tss_thread();
return 0;
}
}
native_thread_t create_native_thread()
{
native_thread_t thread_handle;
int const res = pthread_create(&thread_handle, 0, &test_tss_thread_native, 0);
BOOST_CHECK(!res);
return thread_handle;
}
void join_native_thread(native_thread_t thread)
{
void* result=0;
int const res=pthread_join(thread,&result);
BOOST_CHECK(!res);
}
#endif
void do_test_tss()
@@ -130,19 +100,9 @@ void do_test_tss()
const int NUMTHREADS=5;
boost::thread_group threads;
try
{
for (int i=0; i<NUMTHREADS; ++i)
threads.create_thread(&test_tss_thread);
threads.join_all();
}
catch(...)
{
threads.interrupt_all();
threads.join_all();
throw;
}
for (int i=0; i<NUMTHREADS; ++i)
threads.create_thread(&test_tss_thread);
threads.join_all();
std::cout
<< "tss_instances = " << tss_instances
@@ -153,33 +113,44 @@ void do_test_tss()
BOOST_CHECK_EQUAL(tss_instances, 0);
BOOST_CHECK_EQUAL(tss_total, 5);
tss_instances = 0;
tss_total = 0;
#if defined(BOOST_HAS_WINTHREADS)
tss_instances = 0;
tss_total = 0;
native_thread_t thread1 = create_native_thread();
native_thread_t thread2 = create_native_thread();
native_thread_t thread3 = create_native_thread();
native_thread_t thread4 = create_native_thread();
native_thread_t thread5 = create_native_thread();
native_thread_t thread1 = create_native_thread();
BOOST_CHECK(thread1 != 0);
join_native_thread(thread5);
join_native_thread(thread4);
join_native_thread(thread3);
join_native_thread(thread2);
join_native_thread(thread1);
native_thread_t thread2 = create_native_thread();
BOOST_CHECK(thread2 != 0);
std::cout
<< "tss_instances = " << tss_instances
<< "; tss_total = " << tss_total
<< "\n";
std::cout.flush();
native_thread_t thread3 = create_native_thread();
BOOST_CHECK(thread3 != 0);
// The following is not really an error. TSS cleanup support still is available for boost threads.
// Also this usually will be triggered only when bound to the static version of thread lib.
// 2006-10-02 Roland Schwarz
//BOOST_CHECK_EQUAL(tss_instances, 0);
BOOST_CHECK_MESSAGE(tss_instances == 0, "Support of automatic tss cleanup for native threading API not available");
BOOST_CHECK_EQUAL(tss_total, 5);
native_thread_t thread4 = create_native_thread();
BOOST_CHECK(thread3 != 0);
native_thread_t thread5 = create_native_thread();
BOOST_CHECK(thread3 != 0);
join_native_thread(thread5);
join_native_thread(thread4);
join_native_thread(thread3);
join_native_thread(thread2);
join_native_thread(thread1);
std::cout
<< "tss_instances = " << tss_instances
<< "; tss_total = " << tss_total
<< "\n";
std::cout.flush();
// The following is not really an error. TSS cleanup support still is available for boost threads.
// Also this usually will be triggered only when bound to the static version of thread lib.
// 2006-10-02 Roland Schwarz
//BOOST_CHECK_EQUAL(tss_instances, 0);
BOOST_CHECK_MESSAGE(tss_instances == 0, "Support of automatic tss cleanup for native threading API not available");
BOOST_CHECK_EQUAL(tss_total, 5);
#endif
}
void test_tss()
@@ -187,54 +158,12 @@ void test_tss()
timed_test(&do_test_tss, 2);
}
bool tss_cleanup_called=false;
struct Dummy
{};
void tss_custom_cleanup(Dummy* d)
{
delete d;
tss_cleanup_called=true;
}
boost::thread_specific_ptr<Dummy> tss_with_cleanup(tss_custom_cleanup);
void tss_thread_with_custom_cleanup()
{
tss_with_cleanup.reset(new Dummy);
}
void do_test_tss_with_custom_cleanup()
{
boost::thread t(tss_thread_with_custom_cleanup);
try
{
t.join();
}
catch(...)
{
t.interrupt();
t.join();
throw;
}
BOOST_CHECK(tss_cleanup_called);
}
void test_tss_with_custom_cleanup()
{
timed_test(&do_test_tss_with_custom_cleanup, 2);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: tss test suite");
test->add(BOOST_TEST_CASE(test_tss));
test->add(BOOST_TEST_CASE(test_tss_with_custom_cleanup));
return test;
}

View File

@@ -1,6 +1,5 @@
// Copyright (C) 2001-2003
// William E. Kempf
// Copyright (C) 2007 Anthony Williams
//
// 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)
@@ -155,26 +154,6 @@ thread_binder<F, T> bind(const F& func, const T& param)
{
return thread_binder<F, T>(func, param);
}
template <typename R, typename T>
class thread_member_binder
{
public:
thread_member_binder(R (T::*func)(), T& param)
: func(func), param(param) { }
void operator()() const { (param.*func)(); }
private:
R (T::*func)();
T& param;
};
template <typename R, typename T>
thread_member_binder<R, T> bind(R (T::*func)(), T& param)
{
return thread_member_binder<R, T>(func, param);
}
} // namespace
#endif