mirror of
https://github.com/boostorg/thread.git
synced 2026-02-08 23:22:13 +00:00
Compare commits
170 Commits
boost-1.37
...
sandbox-br
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
01e071233c | ||
|
|
8d22c3869b | ||
|
|
235ed4afe0 | ||
|
|
627cb7f774 | ||
|
|
09021af350 | ||
|
|
31c280d1fa | ||
|
|
629f344f34 | ||
|
|
db5f924e24 | ||
|
|
9be3eb282a | ||
|
|
effd891a16 | ||
|
|
13db35cbf5 | ||
|
|
0f2d480e3c | ||
|
|
9edc61e37b | ||
|
|
f4dab6aac5 | ||
|
|
9e0550d140 | ||
|
|
0d1701c509 | ||
|
|
f2f62f93ea | ||
|
|
8a329f66fb | ||
|
|
05d4c52918 | ||
|
|
8fd0dd0cc0 | ||
|
|
8eea5811ba | ||
|
|
a154c2adab | ||
|
|
10bf4ed576 | ||
|
|
60d12dd395 | ||
|
|
b4e9be3c52 | ||
|
|
dcebae6d4a | ||
|
|
0d776bcd26 | ||
|
|
2d6ed47cf2 | ||
|
|
ea06434425 | ||
|
|
6508eff95e | ||
|
|
69930684a9 | ||
|
|
b1931a3eda | ||
|
|
63b44d4e32 | ||
|
|
f7cb8d8141 | ||
|
|
48c857e02c | ||
|
|
442dc58e0f | ||
|
|
25460c652c | ||
|
|
31a98f0a1e | ||
|
|
36c44b6f45 | ||
|
|
27426b18d1 | ||
|
|
3ea9ce1c8c | ||
|
|
4dfc636c84 | ||
|
|
5fe4312c6c | ||
|
|
63e675a6bb | ||
|
|
e92aeac7d7 | ||
|
|
f1f7eac1f2 | ||
|
|
eff0c84553 | ||
|
|
58c8ce61c7 | ||
|
|
6ac5e6953a | ||
|
|
5d9ad59af2 | ||
|
|
3c48a05437 | ||
|
|
4462124ff2 | ||
|
|
373f557ef7 | ||
|
|
495e561398 | ||
|
|
d24a579033 | ||
|
|
77130424b4 | ||
|
|
eb30688937 | ||
|
|
880bac0633 | ||
|
|
851d6a987f | ||
|
|
9bebd7b35f | ||
|
|
309acb9597 | ||
|
|
a56887167e | ||
|
|
e984dff4e4 | ||
|
|
685e4d446b | ||
|
|
8af680f307 | ||
|
|
6c60cce60d | ||
|
|
5882a675bb | ||
|
|
a5e95845b3 | ||
|
|
5b83d81e40 | ||
|
|
c8e5ad564d | ||
|
|
5edfa273ff | ||
|
|
4db57bcb10 | ||
|
|
3f13340903 | ||
|
|
6abb53c9d3 | ||
|
|
fdd20a519e | ||
|
|
67cc49f333 | ||
|
|
31a34cd0b5 | ||
|
|
ef8c08ba99 | ||
|
|
2991ca6c6f | ||
|
|
52bace18b2 | ||
|
|
767d14ae4f | ||
|
|
1a5c911e36 | ||
|
|
6e42a04e43 | ||
|
|
28be2cfeef | ||
|
|
8be168fd87 | ||
|
|
eee95fef57 | ||
|
|
9ea179b052 | ||
|
|
6868280409 | ||
|
|
e00b764454 | ||
|
|
999613c686 | ||
|
|
c2661d7eb5 | ||
|
|
4d21dd1f47 | ||
|
|
a0a0e57527 | ||
|
|
d8af0d0b4e | ||
|
|
113288e3b0 | ||
|
|
afecfd7c2d | ||
|
|
94d89aac5f | ||
|
|
8831b13efc | ||
|
|
01f99da03a | ||
|
|
080654e3ef | ||
|
|
2ac2eb2a61 | ||
|
|
61b940b705 | ||
|
|
4a4f87e017 | ||
|
|
6d5e7f63a7 | ||
|
|
f77285f375 | ||
|
|
dc5d03a6dc | ||
|
|
ea0961b7f6 | ||
|
|
33d9f9774c | ||
|
|
86097fa038 | ||
|
|
70d9dbc45a | ||
|
|
3926fd3a20 | ||
|
|
7861cf1146 | ||
|
|
0516b86a6e | ||
|
|
ec735d3e9b | ||
|
|
1c5c070983 | ||
|
|
a5c02b73dc | ||
|
|
918b920670 | ||
|
|
de67d2e27e | ||
|
|
bc89df04cb | ||
|
|
c26a4cf082 | ||
|
|
6e1a866b13 | ||
|
|
f91986ad0d | ||
|
|
795cc23f3e | ||
|
|
a3695bd4a0 | ||
|
|
08dc521daf | ||
|
|
8b916d21b1 | ||
|
|
c40f47a78a | ||
|
|
e9fb470b06 | ||
|
|
343d049772 | ||
|
|
86f9480da4 | ||
|
|
8696b610ca | ||
|
|
6f13227eda | ||
|
|
58d5110e61 | ||
|
|
76e53c7bc5 | ||
|
|
cfb08be1a8 | ||
|
|
b5bbb7fb1c | ||
|
|
a76c33f8cc | ||
|
|
810306b8f3 | ||
|
|
6c22bdb3bd | ||
|
|
6a0d3e98bc | ||
|
|
3809321037 | ||
|
|
eef695bdf0 | ||
|
|
ab01ab1e4d | ||
|
|
c8d8a108a7 | ||
|
|
7afd9efcc5 | ||
|
|
56ded87ad2 | ||
|
|
82e503339b | ||
|
|
713d0c7ace | ||
|
|
25ad6e3f8f | ||
|
|
df0197b617 | ||
|
|
a89c4f01ad | ||
|
|
ae67099633 | ||
|
|
57542d3a5c | ||
|
|
9a1da14116 | ||
|
|
ed050d753d | ||
|
|
8bec363710 | ||
|
|
7c68e190a9 | ||
|
|
7ebf5ea3d1 | ||
|
|
11e0435a4b | ||
|
|
d15ee57cd1 | ||
|
|
56d660b7fd | ||
|
|
792958e693 | ||
|
|
914e67dc04 | ||
|
|
b50a7ccb61 | ||
|
|
f827709d42 | ||
|
|
36abb42175 | ||
|
|
40f3b1b4c8 | ||
|
|
4f35e25688 | ||
|
|
270e88edd7 | ||
|
|
5ded171247 |
28
CMakeLists.txt
Normal file
28
CMakeLists.txt
Normal file
@@ -0,0 +1,28 @@
|
||||
#
|
||||
# Copyright Troy D. Straszheim
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# See http://www.boost.org/LICENSE_1_0.txt
|
||||
#
|
||||
#----------------------------------------------------------------------------
|
||||
# This file was automatically generated from the original CMakeLists.txt file
|
||||
# Add a variable to hold the headers for the library
|
||||
set (lib_headers
|
||||
thread.hpp
|
||||
thread
|
||||
)
|
||||
|
||||
# Add a library target to the build system
|
||||
boost_library_project(
|
||||
thread
|
||||
SRCDIRS src
|
||||
TESTDIRS test
|
||||
HEADERS ${lib_headers}
|
||||
# DOCDIRS
|
||||
# DESCRIPTION
|
||||
MODULARIZED
|
||||
# AUTHORS
|
||||
# MAINTAINERS
|
||||
)
|
||||
|
||||
|
||||
@@ -31,25 +31,6 @@ boostbook standalone
|
||||
# Use the main Boost stylesheet:
|
||||
<xsl:param>html.stylesheet=../../../../doc/html/boostbook.css
|
||||
|
||||
# PDF Options:
|
||||
# TOC Generation: this is needed for FOP-0.9 and later:
|
||||
#<xsl:param>fop1.extensions=1
|
||||
# Or enable this if you're using XEP:
|
||||
<xsl:param>xep.extensions=1
|
||||
# TOC generation: this is needed for FOP 0.2, but must not be set to zero for FOP-0.9!
|
||||
<xsl:param>fop.extensions=0
|
||||
# No indent on body text:
|
||||
<xsl:param>body.start.indent=0pt
|
||||
# Margin size:
|
||||
<xsl:param>page.margin.inner=0.5in
|
||||
# Margin size:
|
||||
<xsl:param>page.margin.outer=0.5in
|
||||
# Yes, we want graphics for admonishments:
|
||||
<xsl:param>admon.graphics=1
|
||||
# Set this one for PDF generation *only*:
|
||||
# default pnd graphics are awful in PDF form,
|
||||
# better use SVG's instead:
|
||||
<format>pdf:<xsl:param>admon.graphics.extension=".svg"
|
||||
<format>pdf:<xsl:param>admon.graphics.path=$(boost-images)/
|
||||
;
|
||||
|
||||
|
||||
|
||||
@@ -50,8 +50,9 @@ boost::mutex io_mutex;
|
||||
|
||||
void sender() {
|
||||
int n = 0;
|
||||
while (n < 100) {
|
||||
while (n < 1000000) {
|
||||
buf.send(n);
|
||||
if(!(n%10000))
|
||||
{
|
||||
boost::mutex::scoped_lock io_lock(io_mutex);
|
||||
std::cout << "sent: " << n << std::endl;
|
||||
@@ -65,18 +66,24 @@ void receiver() {
|
||||
int n;
|
||||
do {
|
||||
n = buf.receive();
|
||||
if(!(n%10000))
|
||||
{
|
||||
boost::mutex::scoped_lock io_lock(io_mutex);
|
||||
std::cout << "received: " << n << std::endl;
|
||||
}
|
||||
} while (n != -1); // -1 indicates end of buffer
|
||||
buf.send(-1);
|
||||
}
|
||||
|
||||
int main(int, char*[])
|
||||
{
|
||||
boost::thread thrd1(&sender);
|
||||
boost::thread thrd2(&receiver);
|
||||
boost::thread thrd3(&receiver);
|
||||
boost::thread thrd4(&receiver);
|
||||
thrd1.join();
|
||||
thrd2.join();
|
||||
thrd3.join();
|
||||
thrd4.join();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ int main(int argc, char* argv[])
|
||||
std::cout << "---Noise ON..." << std::endl;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 1000000; ++i)
|
||||
for (int i = 0; i < 1000000000; ++i)
|
||||
cond.notify_all();
|
||||
|
||||
{
|
||||
|
||||
@@ -41,9 +41,9 @@ namespace boost
|
||||
|
||||
#ifndef BOOST_NO_SFINAE
|
||||
template<typename T>
|
||||
typename enable_if<boost::is_convertible<T&,detail::thread_move_t<T> >, T >::type move(T& t)
|
||||
typename enable_if<boost::is_convertible<T&,detail::thread_move_t<T> >, detail::thread_move_t<T> >::type move(T& t)
|
||||
{
|
||||
return T(detail::thread_move_t<T>(t));
|
||||
return detail::thread_move_t<T>(t);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -144,6 +144,9 @@ namespace boost
|
||||
struct dummy;
|
||||
#endif
|
||||
public:
|
||||
#ifdef __SUNPRO_CC
|
||||
thread(const volatile thread&);
|
||||
#endif
|
||||
thread();
|
||||
~thread();
|
||||
|
||||
@@ -201,14 +204,21 @@ namespace boost
|
||||
thread_info=x->thread_info;
|
||||
x->thread_info.reset();
|
||||
}
|
||||
|
||||
|
||||
#ifdef __SUNPRO_CC
|
||||
thread& operator=(thread x)
|
||||
{
|
||||
swap(x);
|
||||
return *this;
|
||||
}
|
||||
#else
|
||||
thread& operator=(detail::thread_move_t<thread> x)
|
||||
{
|
||||
thread new_thread(x);
|
||||
swap(new_thread);
|
||||
return *this;
|
||||
}
|
||||
|
||||
#endif
|
||||
operator detail::thread_move_t<thread>()
|
||||
{
|
||||
return move();
|
||||
@@ -339,9 +349,9 @@ namespace boost
|
||||
return t;
|
||||
}
|
||||
#else
|
||||
inline thread move(detail::thread_move_t<thread> t)
|
||||
inline detail::thread_move_t<thread> move(detail::thread_move_t<thread> t)
|
||||
{
|
||||
return thread(t);
|
||||
return t;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -214,6 +214,9 @@ namespace boost
|
||||
unique_lock& operator=(unique_lock&);
|
||||
unique_lock& operator=(upgrade_lock<Mutex>& other);
|
||||
public:
|
||||
#ifdef __SUNPRO_CC
|
||||
unique_lock(const volatile unique_lock&);
|
||||
#endif
|
||||
unique_lock():
|
||||
m(0),is_locked(false)
|
||||
{}
|
||||
@@ -297,12 +300,20 @@ namespace boost
|
||||
return detail::thread_move_t<unique_lock<Mutex> >(*this);
|
||||
}
|
||||
|
||||
#ifdef __SUNPRO_CC
|
||||
unique_lock& operator=(unique_lock<Mutex> other)
|
||||
{
|
||||
swap(other);
|
||||
return *this;
|
||||
}
|
||||
#else
|
||||
unique_lock& operator=(detail::thread_move_t<unique_lock<Mutex> > other)
|
||||
{
|
||||
unique_lock temp(other);
|
||||
swap(temp);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
unique_lock& operator=(detail::thread_move_t<upgrade_lock<Mutex> > other)
|
||||
{
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <boost/optional.hpp>
|
||||
#include <pthread.h>
|
||||
#include "condition_variable_fwd.hpp"
|
||||
#include <map>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
@@ -22,8 +23,18 @@ namespace boost
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct tss_cleanup_function;
|
||||
struct thread_exit_callback_node;
|
||||
struct tss_data_node;
|
||||
struct tss_data_node
|
||||
{
|
||||
boost::shared_ptr<boost::detail::tss_cleanup_function> func;
|
||||
void* value;
|
||||
|
||||
tss_data_node(boost::shared_ptr<boost::detail::tss_cleanup_function> func_,
|
||||
void* value_):
|
||||
func(func_),value(value_)
|
||||
{}
|
||||
};
|
||||
|
||||
struct thread_data_base;
|
||||
typedef boost::shared_ptr<thread_data_base> thread_data_ptr;
|
||||
@@ -41,14 +52,14 @@ namespace boost
|
||||
bool join_started;
|
||||
bool joined;
|
||||
boost::detail::thread_exit_callback_node* thread_exit_callbacks;
|
||||
boost::detail::tss_data_node* tss_data;
|
||||
std::map<void const*,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)
|
||||
|
||||
@@ -1,111 +1,111 @@
|
||||
#ifndef BOOST_THREAD_TSS_HPP
|
||||
#define BOOST_THREAD_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-8 Anthony Williams
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/thread/detail/thread_heap_alloc.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.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*))
|
||||
{
|
||||
if(func_)
|
||||
{
|
||||
cleanup.reset(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,boost::shared_ptr<detail::tss_cleanup_function>(),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);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
#ifndef BOOST_THREAD_TSS_HPP
|
||||
#define BOOST_THREAD_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-8 Anthony Williams
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/thread/detail/thread_heap_alloc.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.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*))
|
||||
{
|
||||
if(func_)
|
||||
{
|
||||
cleanup.reset(detail::heap_new<run_custom_cleanup_function>(func_),detail::do_heap_delete<run_custom_cleanup_function>());
|
||||
}
|
||||
}
|
||||
~thread_specific_ptr()
|
||||
{
|
||||
detail::set_tss_data(this,boost::shared_ptr<detail::tss_cleanup_function>(),0,true);
|
||||
}
|
||||
|
||||
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,boost::shared_ptr<detail::tss_cleanup_function>(),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);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
|
||||
1
module.cmake
Normal file
1
module.cmake
Normal file
@@ -0,0 +1 @@
|
||||
boost_module(thread DEPENDS date_time bind optional range)
|
||||
21
src/CMakeLists.txt
Normal file
21
src/CMakeLists.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
#
|
||||
# Copyright Troy D. Straszheim
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# See http://www.boost.org/LICENSE_1_0.txt
|
||||
#
|
||||
if (WIN32)
|
||||
set(THREAD_SOURCES win32/thread.cpp win32/exceptions.cpp win32/tss_dll.cpp
|
||||
win32/tss_pe.cpp)
|
||||
else (WIN32)
|
||||
set(THREAD_SOURCES pthread/thread.cpp pthread/exceptions.cpp pthread/once.cpp)
|
||||
endif (WIN32)
|
||||
|
||||
boost_add_library(
|
||||
boost_thread
|
||||
${THREAD_SOURCES}
|
||||
SHARED_COMPILE_FLAGS "-DBOOST_THREAD_BUILD_DLL=1"
|
||||
STATIC_COMPILE_FLAGS "-DBOOST_THREAD_BUILD_LIB=1"
|
||||
NO_SINGLE_THREADED
|
||||
)
|
||||
|
||||
@@ -42,19 +42,6 @@ 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
|
||||
{
|
||||
boost::once_flag current_thread_tls_init_flag=BOOST_ONCE_INIT;
|
||||
@@ -67,7 +54,7 @@ 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->tss_data.empty() || thread_info->thread_exit_callbacks)
|
||||
{
|
||||
while(thread_info->thread_exit_callbacks)
|
||||
{
|
||||
@@ -80,15 +67,18 @@ namespace boost
|
||||
}
|
||||
delete current_node;
|
||||
}
|
||||
while(thread_info->tss_data)
|
||||
for(std::map<void const*,tss_data_node>::iterator next=thread_info->tss_data.begin(),
|
||||
current,
|
||||
end=thread_info->tss_data.end();
|
||||
next!=end;)
|
||||
{
|
||||
detail::tss_data_node* const current_node=thread_info->tss_data;
|
||||
thread_info->tss_data=current_node->next;
|
||||
if(current_node->func)
|
||||
current=next;
|
||||
++next;
|
||||
if(current->second.func && current->second.value)
|
||||
{
|
||||
(*current_node->func)(current_node->value);
|
||||
(*current->second.func)(current->second.value);
|
||||
}
|
||||
delete current_node;
|
||||
thread_info->tss_data.erase(current);
|
||||
}
|
||||
}
|
||||
thread_info->self.reset();
|
||||
@@ -132,10 +122,12 @@ namespace boost
|
||||
catch(thread_interrupted const&)
|
||||
{
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
std::terminate();
|
||||
}
|
||||
// Removed as it stops the debugger identifying the cause of the exception
|
||||
// Unhandled exceptions still cause the application to terminate
|
||||
// catch(...)
|
||||
// {
|
||||
// std::terminate();
|
||||
// }
|
||||
|
||||
detail::tls_destructor(thread_info.get());
|
||||
detail::set_current_thread_data(0);
|
||||
@@ -388,7 +380,7 @@ namespace boost
|
||||
{
|
||||
#if defined(PTW32_VERSION) || defined(__hpux)
|
||||
return pthread_num_processors_np();
|
||||
#elif defined(__linux__)
|
||||
#elif defined(_GNU_SOURCE)
|
||||
return get_nprocs();
|
||||
#elif defined(__APPLE__) || defined(__FreeBSD__)
|
||||
int count;
|
||||
@@ -550,14 +542,11 @@ namespace boost
|
||||
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)
|
||||
std::map<void const*,tss_data_node>::iterator current_node=
|
||||
current_thread_data->tss_data.find(key);
|
||||
if(current_node!=current_thread_data->tss_data.end())
|
||||
{
|
||||
if(current_node->key==key)
|
||||
{
|
||||
return current_node;
|
||||
}
|
||||
current_node=current_node->next;
|
||||
return ¤t_node->second;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
@@ -571,106 +560,47 @@ namespace boost
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void add_new_tss_node(void const* key,
|
||||
boost::shared_ptr<tss_cleanup_function> func,
|
||||
void* tss_data)
|
||||
{
|
||||
detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
|
||||
current_thread_data->tss_data.insert(std::make_pair(key,tss_data_node(func,tss_data)));
|
||||
}
|
||||
|
||||
void erase_tss_node(void const* key)
|
||||
{
|
||||
detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
|
||||
current_thread_data->tss_data.erase(key);
|
||||
}
|
||||
|
||||
void set_tss_data(void const* key,boost::shared_ptr<tss_cleanup_function> func,void* tss_data,bool cleanup_existing)
|
||||
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)
|
||||
if(cleanup_existing && current_node->func && current_node->value)
|
||||
{
|
||||
(*current_node->func)(current_node->value);
|
||||
}
|
||||
current_node->func=func;
|
||||
current_node->value=tss_data;
|
||||
if(func || tss_data)
|
||||
{
|
||||
current_node->func=func;
|
||||
current_node->value=tss_data;
|
||||
}
|
||||
else
|
||||
{
|
||||
erase_tss_node(key);
|
||||
}
|
||||
}
|
||||
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;
|
||||
add_new_tss_node(key,func,tss_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// thread_group::thread_group()
|
||||
// {
|
||||
// }
|
||||
|
||||
// thread_group::~thread_group()
|
||||
// {
|
||||
// // We shouldn't have to scoped_lock here, since referencing this object
|
||||
// // from another thread while we're deleting it in the current thread is
|
||||
// // going to lead to undefined behavior any way.
|
||||
// for (std::list<thread*>::iterator it = m_threads.begin();
|
||||
// it != m_threads.end(); ++it)
|
||||
// {
|
||||
// delete (*it);
|
||||
// }
|
||||
// }
|
||||
|
||||
// thread* thread_group::create_thread(const function0<void>& threadfunc)
|
||||
// {
|
||||
// // No scoped_lock required here since the only "shared data" that's
|
||||
// // modified here occurs inside add_thread which does scoped_lock.
|
||||
// std::auto_ptr<thread> thrd(new thread(threadfunc));
|
||||
// add_thread(thrd.get());
|
||||
// return thrd.release();
|
||||
// }
|
||||
|
||||
// void thread_group::add_thread(thread* thrd)
|
||||
// {
|
||||
// mutex::scoped_lock scoped_lock(m_mutex);
|
||||
|
||||
// // For now we'll simply ignore requests to add a thread object multiple
|
||||
// // times. Should we consider this an error and either throw or return an
|
||||
// // error value?
|
||||
// std::list<thread*>::iterator it = std::find(m_threads.begin(),
|
||||
// m_threads.end(), thrd);
|
||||
// BOOST_ASSERT(it == m_threads.end());
|
||||
// if (it == m_threads.end())
|
||||
// m_threads.push_back(thrd);
|
||||
// }
|
||||
|
||||
// void thread_group::remove_thread(thread* thrd)
|
||||
// {
|
||||
// mutex::scoped_lock scoped_lock(m_mutex);
|
||||
|
||||
// // For now we'll simply ignore requests to remove a thread object that's
|
||||
// // not in the group. Should we consider this an error and either throw or
|
||||
// // return an error value?
|
||||
// std::list<thread*>::iterator it = std::find(m_threads.begin(),
|
||||
// m_threads.end(), thrd);
|
||||
// BOOST_ASSERT(it != m_threads.end());
|
||||
// if (it != m_threads.end())
|
||||
// m_threads.erase(it);
|
||||
// }
|
||||
|
||||
// void thread_group::join_all()
|
||||
// {
|
||||
// mutex::scoped_lock scoped_lock(m_mutex);
|
||||
// for (std::list<thread*>::iterator it = m_threads.begin();
|
||||
// it != m_threads.end(); ++it)
|
||||
// {
|
||||
// (*it)->join();
|
||||
// }
|
||||
// }
|
||||
|
||||
// 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();
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
// size_t thread_group::size() const
|
||||
// {
|
||||
// return m_threads.size();
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
@@ -169,10 +169,12 @@ namespace boost
|
||||
catch(thread_interrupted const&)
|
||||
{
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
std::terminate();
|
||||
}
|
||||
// Removed as it stops the debugger identifying the cause of the exception
|
||||
// Unhandled exceptions still cause the application to terminate
|
||||
// catch(...)
|
||||
// {
|
||||
// std::terminate();
|
||||
// }
|
||||
run_thread_exit_callbacks();
|
||||
return 0;
|
||||
}
|
||||
@@ -559,7 +561,7 @@ namespace boost
|
||||
{
|
||||
if(tss_data_node* const current_node=find_tss_data(key))
|
||||
{
|
||||
if(cleanup_existing && current_node->func.get())
|
||||
if(cleanup_existing && current_node->func.get() && current_node->value)
|
||||
{
|
||||
(*current_node->func)(current_node->value);
|
||||
}
|
||||
|
||||
39
test/CMakeLists.txt
Normal file
39
test/CMakeLists.txt
Normal file
@@ -0,0 +1,39 @@
|
||||
#
|
||||
# Copyright Troy D. Straszheim
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# See http://www.boost.org/LICENSE_1_0.txt
|
||||
#
|
||||
boost_additional_test_dependencies(thread BOOST_DEPENDS test )
|
||||
|
||||
|
||||
|
||||
set(TESTS
|
||||
test_thread
|
||||
test_thread_id
|
||||
test_hardware_concurrency
|
||||
test_thread_move
|
||||
test_thread_launching
|
||||
test_thread_mf
|
||||
test_move_function
|
||||
test_mutex
|
||||
test_condition_notify_one
|
||||
test_condition_timed_wait_times_out
|
||||
test_condition_notify_all
|
||||
test_condition
|
||||
test_tss
|
||||
test_once
|
||||
test_xtime
|
||||
test_barrier
|
||||
test_shared_mutex
|
||||
test_shared_mutex_part_2
|
||||
test_shared_mutex_timed_locks
|
||||
test_lock_concept
|
||||
test_generic_locks)
|
||||
|
||||
foreach (TEST ${TESTS})
|
||||
boost_test_run(${TEST} MULTI_THREADED DEPENDS boost_thread boost_unit_test_framework)
|
||||
endforeach (TEST ${TESTS})
|
||||
|
||||
boost_test_compile_fail(no_implicit_move_from_lvalue_thread)
|
||||
boost_test_compile_fail(no_implicit_assign_from_lvalue_thread)
|
||||
@@ -38,6 +38,8 @@ rule thread-run ( sources )
|
||||
[ thread-run test_thread_id.cpp ]
|
||||
[ thread-run test_hardware_concurrency.cpp ]
|
||||
[ thread-run test_thread_move.cpp ]
|
||||
[ thread-run test_thread_return_local.cpp ]
|
||||
[ thread-run test_thread_move_return.cpp ]
|
||||
[ thread-run test_thread_launching.cpp ]
|
||||
[ thread-run test_thread_mf.cpp ]
|
||||
[ thread-run test_move_function.cpp ]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2007 Anthony Williams
|
||||
// Copyright (C) 2007-9 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)
|
||||
@@ -33,21 +33,6 @@ void test_move_from_function_return()
|
||||
BOOST_CHECK_EQUAL(the_id,x_id);
|
||||
}
|
||||
|
||||
boost::thread make_thread_return_lvalue(boost::thread::id* the_id)
|
||||
{
|
||||
boost::thread t(do_nothing,the_id);
|
||||
return boost::move(t);
|
||||
}
|
||||
|
||||
void test_move_from_function_return_lvalue()
|
||||
{
|
||||
boost::thread::id the_id;
|
||||
boost::thread x=make_thread_return_lvalue(&the_id);
|
||||
boost::thread::id x_id=x.get_id();
|
||||
x.join();
|
||||
BOOST_CHECK_EQUAL(the_id,x_id);
|
||||
}
|
||||
|
||||
void test_move_assign()
|
||||
{
|
||||
boost::thread::id the_id;
|
||||
@@ -66,7 +51,6 @@ boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
|
||||
test->add(BOOST_TEST_CASE(test_move_on_construction));
|
||||
test->add(BOOST_TEST_CASE(test_move_from_function_return));
|
||||
test->add(BOOST_TEST_CASE(test_move_from_function_return_lvalue));
|
||||
test->add(BOOST_TEST_CASE(test_move_assign));
|
||||
return test;
|
||||
}
|
||||
|
||||
35
test/test_thread_move_return.cpp
Normal file
35
test/test_thread_move_return.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
// Copyright (C) 2009 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(boost::thread::id* my_id)
|
||||
{
|
||||
*my_id=boost::this_thread::get_id();
|
||||
}
|
||||
|
||||
boost::thread make_thread_move_return(boost::thread::id* the_id)
|
||||
{
|
||||
boost::thread t(do_nothing,the_id);
|
||||
return boost::move(t);
|
||||
}
|
||||
|
||||
void test_move_from_function_move_return()
|
||||
{
|
||||
boost::thread::id the_id;
|
||||
boost::thread x=make_thread_move_return(&the_id);
|
||||
boost::thread::id x_id=x.get_id();
|
||||
x.join();
|
||||
BOOST_CHECK_EQUAL(the_id,x_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_move_from_function_move_return));
|
||||
return test;
|
||||
}
|
||||
35
test/test_thread_return_local.cpp
Normal file
35
test/test_thread_return_local.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
// Copyright (C) 2009 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(boost::thread::id* my_id)
|
||||
{
|
||||
*my_id=boost::this_thread::get_id();
|
||||
}
|
||||
|
||||
boost::thread make_thread_return_local(boost::thread::id* the_id)
|
||||
{
|
||||
boost::thread t(do_nothing,the_id);
|
||||
return t;
|
||||
}
|
||||
|
||||
void test_move_from_function_return_local()
|
||||
{
|
||||
boost::thread::id the_id;
|
||||
boost::thread x=make_thread_return_local(&the_id);
|
||||
boost::thread::id x_id=x.get_id();
|
||||
x.join();
|
||||
BOOST_CHECK_EQUAL(the_id,x_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_move_from_function_return_local));
|
||||
return test;
|
||||
}
|
||||
@@ -310,6 +310,39 @@ void test_tss_does_no_cleanup_with_null_cleanup_function()
|
||||
timed_test(&do_test_tss_does_no_cleanup_with_null_cleanup_function, 2);
|
||||
}
|
||||
|
||||
void thread_with_local_tss_ptr()
|
||||
{
|
||||
{
|
||||
boost::thread_specific_ptr<Dummy> local_tss(tss_custom_cleanup);
|
||||
|
||||
local_tss.reset(new Dummy);
|
||||
}
|
||||
BOOST_CHECK(tss_cleanup_called);
|
||||
tss_cleanup_called=false;
|
||||
}
|
||||
|
||||
|
||||
void test_tss_does_not_call_cleanup_after_ptr_destroyed()
|
||||
{
|
||||
boost::thread t(thread_with_local_tss_ptr);
|
||||
t.join();
|
||||
BOOST_CHECK(!tss_cleanup_called);
|
||||
}
|
||||
|
||||
void test_tss_cleanup_not_called_for_null_pointer()
|
||||
{
|
||||
boost::thread_specific_ptr<Dummy> local_tss(tss_custom_cleanup);
|
||||
local_tss.reset(new Dummy);
|
||||
tss_cleanup_called=false;
|
||||
local_tss.reset(0);
|
||||
BOOST_CHECK(tss_cleanup_called);
|
||||
tss_cleanup_called=false;
|
||||
local_tss.reset(new Dummy);
|
||||
BOOST_CHECK(!tss_cleanup_called);
|
||||
}
|
||||
|
||||
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
@@ -319,6 +352,8 @@ boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
test->add(BOOST_TEST_CASE(test_tss_with_custom_cleanup));
|
||||
test->add(BOOST_TEST_CASE(test_tss_does_no_cleanup_after_release));
|
||||
test->add(BOOST_TEST_CASE(test_tss_does_no_cleanup_with_null_cleanup_function));
|
||||
test->add(BOOST_TEST_CASE(test_tss_does_not_call_cleanup_after_ptr_destroyed));
|
||||
test->add(BOOST_TEST_CASE(test_tss_cleanup_not_called_for_null_pointer));
|
||||
|
||||
return test;
|
||||
}
|
||||
|
||||
366
test/util.inl
366
test/util.inl
@@ -1,183 +1,183 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
// Copyright (C) 2007-8 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)
|
||||
|
||||
#if !defined(UTIL_INL_WEK01242003)
|
||||
#define UTIL_INL_WEK01242003
|
||||
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
#ifndef DEFAULT_EXECUTION_MONITOR_TYPE
|
||||
# define DEFAULT_EXECUTION_MONITOR_TYPE execution_monitor::use_condition
|
||||
#endif
|
||||
|
||||
// boostinspect:nounnamed
|
||||
|
||||
namespace
|
||||
{
|
||||
inline boost::xtime delay(int secs, int msecs=0, int nsecs=0)
|
||||
{
|
||||
const int MILLISECONDS_PER_SECOND = 1000;
|
||||
const int NANOSECONDS_PER_SECOND = 1000000000;
|
||||
const int NANOSECONDS_PER_MILLISECOND = 1000000;
|
||||
|
||||
boost::xtime xt;
|
||||
if (boost::TIME_UTC != boost::xtime_get (&xt, boost::TIME_UTC))
|
||||
BOOST_ERROR ("boost::xtime_get != boost::TIME_UTC");
|
||||
|
||||
nsecs += xt.nsec;
|
||||
msecs += nsecs / NANOSECONDS_PER_MILLISECOND;
|
||||
secs += msecs / MILLISECONDS_PER_SECOND;
|
||||
nsecs += (msecs % MILLISECONDS_PER_SECOND) * NANOSECONDS_PER_MILLISECOND;
|
||||
xt.nsec = nsecs % NANOSECONDS_PER_SECOND;
|
||||
xt.sec += secs + (nsecs / NANOSECONDS_PER_SECOND);
|
||||
|
||||
return xt;
|
||||
}
|
||||
|
||||
inline bool in_range(const boost::xtime& xt, int secs=1)
|
||||
{
|
||||
boost::xtime min = delay(-secs);
|
||||
boost::xtime max = delay(0);
|
||||
return (boost::xtime_cmp(xt, min) >= 0) &&
|
||||
(boost::xtime_cmp(xt, max) <= 0);
|
||||
}
|
||||
|
||||
class execution_monitor
|
||||
{
|
||||
public:
|
||||
enum wait_type { use_sleep_only, use_mutex, use_condition };
|
||||
|
||||
execution_monitor(wait_type type, int secs)
|
||||
: done(false), type(type), secs(secs) { }
|
||||
void start()
|
||||
{
|
||||
if (type != use_sleep_only) {
|
||||
boost::mutex::scoped_lock lock(mutex); done = false;
|
||||
} else {
|
||||
done = false;
|
||||
}
|
||||
}
|
||||
void finish()
|
||||
{
|
||||
if (type != use_sleep_only) {
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
done = true;
|
||||
if (type == use_condition)
|
||||
cond.notify_one();
|
||||
} else {
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
bool wait()
|
||||
{
|
||||
boost::xtime xt = delay(secs);
|
||||
if (type != use_condition)
|
||||
boost::thread::sleep(xt);
|
||||
if (type != use_sleep_only) {
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
while (type == use_condition && !done) {
|
||||
if (!cond.timed_wait(lock, xt))
|
||||
break;
|
||||
}
|
||||
return done;
|
||||
}
|
||||
return done;
|
||||
}
|
||||
|
||||
private:
|
||||
boost::mutex mutex;
|
||||
boost::condition cond;
|
||||
bool done;
|
||||
wait_type type;
|
||||
int secs;
|
||||
};
|
||||
|
||||
template <typename F>
|
||||
class indirect_adapter
|
||||
{
|
||||
public:
|
||||
indirect_adapter(F func, execution_monitor& monitor)
|
||||
: func(func), monitor(monitor) { }
|
||||
void operator()() const
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::thread thrd(func);
|
||||
thrd.join();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
monitor.finish();
|
||||
throw;
|
||||
}
|
||||
monitor.finish();
|
||||
}
|
||||
|
||||
private:
|
||||
F func;
|
||||
execution_monitor& monitor;
|
||||
void operator=(indirect_adapter&);
|
||||
};
|
||||
|
||||
template <typename F>
|
||||
void timed_test(F func, int secs,
|
||||
execution_monitor::wait_type type=DEFAULT_EXECUTION_MONITOR_TYPE)
|
||||
{
|
||||
execution_monitor monitor(type, secs);
|
||||
indirect_adapter<F> ifunc(func, monitor);
|
||||
monitor.start();
|
||||
boost::thread thrd(ifunc);
|
||||
BOOST_REQUIRE_MESSAGE(monitor.wait(),
|
||||
"Timed test didn't complete in time, possible deadlock.");
|
||||
}
|
||||
|
||||
template <typename F, typename T>
|
||||
class thread_binder
|
||||
{
|
||||
public:
|
||||
thread_binder(const F& func, const T& param)
|
||||
: func(func), param(param) { }
|
||||
void operator()() const { func(param); }
|
||||
|
||||
private:
|
||||
F func;
|
||||
T param;
|
||||
};
|
||||
|
||||
template <typename F, typename T>
|
||||
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:
|
||||
void operator=(thread_member_binder&);
|
||||
|
||||
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
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
// Copyright (C) 2007-8 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)
|
||||
|
||||
#if !defined(UTIL_INL_WEK01242003)
|
||||
#define UTIL_INL_WEK01242003
|
||||
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
#ifndef DEFAULT_EXECUTION_MONITOR_TYPE
|
||||
# define DEFAULT_EXECUTION_MONITOR_TYPE execution_monitor::use_condition
|
||||
#endif
|
||||
|
||||
// boostinspect:nounnamed
|
||||
|
||||
namespace
|
||||
{
|
||||
inline boost::xtime delay(int secs, int msecs=0, int nsecs=0)
|
||||
{
|
||||
const int MILLISECONDS_PER_SECOND = 1000;
|
||||
const int NANOSECONDS_PER_SECOND = 1000000000;
|
||||
const int NANOSECONDS_PER_MILLISECOND = 1000000;
|
||||
|
||||
boost::xtime xt;
|
||||
if (boost::TIME_UTC != boost::xtime_get (&xt, boost::TIME_UTC))
|
||||
BOOST_ERROR ("boost::xtime_get != boost::TIME_UTC");
|
||||
|
||||
nsecs += xt.nsec;
|
||||
msecs += nsecs / NANOSECONDS_PER_MILLISECOND;
|
||||
secs += msecs / MILLISECONDS_PER_SECOND;
|
||||
nsecs += (msecs % MILLISECONDS_PER_SECOND) * NANOSECONDS_PER_MILLISECOND;
|
||||
xt.nsec = nsecs % NANOSECONDS_PER_SECOND;
|
||||
xt.sec += secs + (nsecs / NANOSECONDS_PER_SECOND);
|
||||
|
||||
return xt;
|
||||
}
|
||||
|
||||
inline bool in_range(const boost::xtime& xt, int secs=1)
|
||||
{
|
||||
boost::xtime min = delay(-secs);
|
||||
boost::xtime max = delay(0);
|
||||
return (boost::xtime_cmp(xt, min) >= 0) &&
|
||||
(boost::xtime_cmp(xt, max) <= 0);
|
||||
}
|
||||
|
||||
class execution_monitor
|
||||
{
|
||||
public:
|
||||
enum wait_type { use_sleep_only, use_mutex, use_condition };
|
||||
|
||||
execution_monitor(wait_type type, int secs)
|
||||
: done(false), type(type), secs(secs) { }
|
||||
void start()
|
||||
{
|
||||
if (type != use_sleep_only) {
|
||||
boost::mutex::scoped_lock lock(mutex); done = false;
|
||||
} else {
|
||||
done = false;
|
||||
}
|
||||
}
|
||||
void finish()
|
||||
{
|
||||
if (type != use_sleep_only) {
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
done = true;
|
||||
if (type == use_condition)
|
||||
cond.notify_one();
|
||||
} else {
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
bool wait()
|
||||
{
|
||||
boost::xtime xt = delay(secs);
|
||||
if (type != use_condition)
|
||||
boost::thread::sleep(xt);
|
||||
if (type != use_sleep_only) {
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
while (type == use_condition && !done) {
|
||||
if (!cond.timed_wait(lock, xt))
|
||||
break;
|
||||
}
|
||||
return done;
|
||||
}
|
||||
return done;
|
||||
}
|
||||
|
||||
private:
|
||||
boost::mutex mutex;
|
||||
boost::condition cond;
|
||||
bool done;
|
||||
wait_type type;
|
||||
int secs;
|
||||
};
|
||||
|
||||
template <typename F>
|
||||
class indirect_adapter
|
||||
{
|
||||
public:
|
||||
indirect_adapter(F func, execution_monitor& monitor)
|
||||
: func(func), monitor(monitor) { }
|
||||
void operator()() const
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::thread thrd(func);
|
||||
thrd.join();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
monitor.finish();
|
||||
throw;
|
||||
}
|
||||
monitor.finish();
|
||||
}
|
||||
|
||||
private:
|
||||
F func;
|
||||
execution_monitor& monitor;
|
||||
void operator=(indirect_adapter&);
|
||||
};
|
||||
|
||||
template <typename F>
|
||||
void timed_test(F func, int secs,
|
||||
execution_monitor::wait_type type=DEFAULT_EXECUTION_MONITOR_TYPE)
|
||||
{
|
||||
execution_monitor monitor(type, secs);
|
||||
indirect_adapter<F> ifunc(func, monitor);
|
||||
monitor.start();
|
||||
boost::thread thrd(ifunc);
|
||||
BOOST_REQUIRE_MESSAGE(monitor.wait(),
|
||||
"Timed test didn't complete in time, possible deadlock.");
|
||||
}
|
||||
|
||||
template <typename F, typename T>
|
||||
class thread_binder
|
||||
{
|
||||
public:
|
||||
thread_binder(const F& func, const T& param)
|
||||
: func(func), param(param) { }
|
||||
void operator()() const { func(param); }
|
||||
|
||||
private:
|
||||
F func;
|
||||
T param;
|
||||
};
|
||||
|
||||
template <typename F, typename T>
|
||||
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:
|
||||
void operator=(thread_member_binder&);
|
||||
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user