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

Compare commits

...

6 Commits

Author SHA1 Message Date
Vladimir Prus
3737fcfeb3 Create maintenance branch for 1.41.
[SVN r57781]
2009-11-19 06:09:27 +00:00
Beman Dawes
b94b1ab8e5 Release 1.41.0
[SVN r57747]
2009-11-18 14:58:26 +00:00
Anthony Williams
9087fd904d Merged documentation changes to boost.thread (re at_thread_exit) from trunk
[SVN r57381]
2009-11-04 21:48:18 +00:00
Anthony Williams
66ac6942b6 Merged boost.thread changes from trunk
[SVN r57243]
2009-10-30 09:50:13 +00:00
Anthony Williams
20980fe54d Merged thread changes from trunk
[SVN r56992]
2009-10-19 09:18:13 +00:00
Troy D. Straszheim
fb54acfe69 rm cmake from the release branch before it goes out broken. Policy dictates that you never commit to release, you commit to trunk and merge to release.
[SVN r56941]
2009-10-17 01:10:45 +00:00
35 changed files with 4361 additions and 764 deletions

View File

@@ -1,28 +0,0 @@
#
# 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
)

View File

@@ -180,7 +180,6 @@ rule requirements ( properties * )
alias thread_sources
: ## win32 sources ##
win32/thread.cpp
win32/exceptions.cpp
win32/tss_dll.cpp
win32/tss_pe.cpp
: ## requirements ##
@@ -190,7 +189,6 @@ alias thread_sources
alias thread_sources
: ## pthread sources ##
pthread/thread.cpp
pthread/exceptions.cpp
pthread/once.cpp
: ## requirements ##
<threadapi>pthread

View File

@@ -5,7 +5,11 @@
http://www.boost.org/LICENSE_1_0.txt).
]
[section:changes Changes since boost 1.35]
[section:changes Changes since boost 1.40]
The 1.41.0 release of Boost adds futures to the thread library. There are also a few minor changes.
[heading Changes since boost 1.35]
The 1.36.0 release of Boost includes a few new features in the thread library:

968
doc/future_ref.qbk Normal file
View File

@@ -0,0 +1,968 @@
[/
(C) Copyright 2008-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).
]
[section:reference Futures Reference]
[section:future_state `state` enum]
namespace future_state
{
enum state {uninitialized, waiting, ready};
}
[endsect]
[section:unique_future `unique_future` class template]
template <typename R>
class unique_future
{
unique_future(unique_future & rhs);// = delete;
unique_future& operator=(unique_future& rhs);// = delete;
public:
typedef future_state::state state;
unique_future();
~unique_future();
// move support
unique_future(unique_future && other);
unique_future& operator=(unique_future && other);
void swap(unique_future& other);
// retrieving the value
R&& get();
// functions to check state
state get_state() const;
bool is_ready() const;
bool has_exception() const;
bool has_value() const;
// waiting for the result to be ready
void wait() const;
template<typename Duration>
bool timed_wait(Duration const& rel_time) const;
bool timed_wait_until(boost::system_time const& abs_time) const;
};
[section:default_constructor Default Constructor]
unique_future();
[variablelist
[[Effects:] [Constructs an uninitialized future.]]
[[Postconditions:] [[unique_future_is_ready_link `this->is_ready`] returns `false`. [unique_future_get_state_link
`this->get_state()`] returns __uninitialized__.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:destructor Destructor]
~unique_future();
[variablelist
[[Effects:] [Destroys `*this`.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:move_constructor Move Constructor]
unique_future(unique_future && other);
[variablelist
[[Effects:] [Constructs a new future, and transfers ownership of the asynchronous result associated with `other` to `*this`.]]
[[Postconditions:] [[unique_future_get_state_link `this->get_state()`] returns the value of `other->get_state()` prior to the
call. `other->get_state()` returns __uninitialized__. If `other` was associated with an asynchronous result, that result is now
associated with `*this`. `other` is not associated with any asynchronous result.]]
[[Throws:] [Nothing.]]
[[Notes:] [If the compiler does not support rvalue-references, this is implemented using the boost.thread move emulation.]]
]
[endsect]
[section:move_assignment Move Assignment Operator]
unique_future& operator=(unique_future && other);
[variablelist
[[Effects:] [Transfers ownership of the asynchronous result associated with `other` to `*this`.]]
[[Postconditions:] [[unique_future_get_state_link `this->get_state()`] returns the value of `other->get_state()` prior to the
call. `other->get_state()` returns __uninitialized__. If `other` was associated with an asynchronous result, that result is now
associated with `*this`. `other` is not associated with any asynchronous result. If `*this` was associated with an asynchronous
result prior to the call, that result no longer has an associated __unique_future__ instance.]]
[[Throws:] [Nothing.]]
[[Notes:] [If the compiler does not support rvalue-references, this is implemented using the boost.thread move emulation.]]
]
[endsect]
[section:swap Member function `swap()`]
void swap(unique_future & other);
[variablelist
[[Effects:] [Swaps ownership of the asynchronous results associated with `other` and `*this`.]]
[[Postconditions:] [[unique_future_get_state_link `this->get_state()`] returns the value of `other->get_state()` prior to the
call. `other->get_state()` returns the value of `this->get_state()` prior to the call. If `other` was associated with an
asynchronous result, that result is now associated with `*this`, otherwise `*this` has no associated result. If `*this` was
associated with an asynchronous result, that result is now associated with `other`, otherwise `other` has no associated result.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:get Member function `get()`]
R&& get();
R& unique_future<R&>::get();
void unique_future<void>::get();
[variablelist
[[Effects:] [If `*this` is associated with an asynchronous result, waits until the result is ready as-if by a call to
__unique_future_wait__, and retrieves the result (whether that is a value or an exception).]]
[[Returns:] [If the result type `R` is a reference, returns the stored reference. If `R` is `void`, there is no return
value. Otherwise, returns an rvalue-reference to the value stored in the asynchronous result.]]
[[Postconditions:] [[unique_future_is_ready_link `this->is_ready()`] returns `true`. [unique_future_get_state_link
`this->get_state()`] returns __ready__.]]
[[Throws:] [__future_uninitialized__ if `*this` is not associated with an asynchronous result. __thread_interrupted__ if the result
associated with `*this` is not ready at the point of the call, and the current thread is interrupted. Any exception stored in the
asynchronous result in place of a value.]]
[[Notes:] [`get()` is an ['interruption point].]]
]
[endsect]
[section:wait Member function `wait()`]
void wait();
[variablelist
[[Effects:] [If `*this` is associated with an asynchronous result, waits until the result is ready. If the result is not ready on
entry, and the result has a ['wait callback] set, that callback is invoked prior to waiting.]]
[[Throws:] [__future_uninitialized__ if `*this` is not associated with an asynchronous result. __thread_interrupted__ if the result
associated with `*this` is not ready at the point of the call, and the current thread is interrupted. Any exception thrown by the
['wait callback] if such a callback is called.]]
[[Postconditions:] [[unique_future_is_ready_link `this->is_ready()`] returns `true`. [unique_future_get_state_link
`this->get_state()`] returns __ready__.]]
[[Notes:] [`wait()` is an ['interruption point].]]
]
[endsect]
[section:timed_wait_duration Member function `timed_wait()`]
template<typename Duration>
bool timed_wait(Duration const& wait_duration);
[variablelist
[[Effects:] [If `*this` is associated with an asynchronous result, waits until the result is ready, or the time specified by
`wait_duration` has elapsed. If the result is not ready on entry, and the result has a ['wait callback] set, that callback is
invoked prior to waiting.]]
[[Returns:] [`true` if `*this` is associated with an asynchronous result, and that result is ready before the specified time has
elapsed, `false` otherwise.]]
[[Throws:] [__future_uninitialized__ if `*this` is not associated with an asynchronous result. __thread_interrupted__ if the result
associated with `*this` is not ready at the point of the call, and the current thread is interrupted. Any exception thrown by the
['wait callback] if such a callback is called.]]
[[Postconditions:] [If this call returned `true`, then [unique_future_is_ready_link `this->is_ready()`] returns `true` and
[unique_future_get_state_link `this->get_state()`] returns __ready__.]]
[[Notes:] [`timed_wait()` is an ['interruption point]. `Duration` must be a type that meets the Boost.DateTime time duration requirements.]]
]
[endsect]
[section:timed_wait_absolute Member function `timed_wait()`]
bool timed_wait(boost::system_time const& wait_timeout);
[variablelist
[[Effects:] [If `*this` is associated with an asynchronous result, waits until the result is ready, or the time point specified by
`wait_timeout` has passed. If the result is not ready on entry, and the result has a ['wait callback] set, that callback is invoked
prior to waiting.]]
[[Returns:] [`true` if `*this` is associated with an asynchronous result, and that result is ready before the specified time has
passed, `false` otherwise.]]
[[Throws:] [__future_uninitialized__ if `*this` is not associated with an asynchronous result. __thread_interrupted__ if the result
associated with `*this` is not ready at the point of the call, and the current thread is interrupted. Any exception thrown by the
['wait callback] if such a callback is called.]]
[[Postconditions:] [If this call returned `true`, then [unique_future_is_ready_link `this->is_ready()`] returns `true` and
[unique_future_get_state_link `this->get_state()`] returns __ready__.]]
[[Notes:] [`timed_wait()` is an ['interruption point].]]
]
[endsect]
[section:is_ready Member function `is_ready()`]
bool is_ready();
[variablelist
[[Effects:] [Checks to see if the asynchronous result associated with `*this` is set.]]
[[Returns:] [`true` if `*this` is associated with an asynchronous result, and that result is ready for retrieval, `false`
otherwise.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:has_value Member function `has_value()`]
bool has_value();
[variablelist
[[Effects:] [Checks to see if the asynchronous result associated with `*this` is set with a value rather than an exception.]]
[[Returns:] [`true` if `*this` is associated with an asynchronous result, that result is ready for retrieval, and the result is a
stored value, `false` otherwise.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:has_exception Member function `has_exception()`]
bool has_exception();
[variablelist
[[Effects:] [Checks to see if the asynchronous result associated with `*this` is set with an exception rather than a value.]]
[[Returns:] [`true` if `*this` is associated with an asynchronous result, that result is ready for retrieval, and the result is a
stored exception, `false` otherwise.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:get_state Member function `get_state()`]
future_state::state get_state();
[variablelist
[[Effects:] [Determine the state of the asynchronous result associated with `*this`, if any.]]
[[Returns:] [__uninitialized__ if `*this` is not associated with an asynchronous result. __ready__ if the asynchronous result
associated with `*this` is ready for retrieval, __waiting__ otherwise.]]
[[Throws:] [Nothing.]]
]
[endsect]
[endsect]
[section:shared_future `shared_future` class template]
template <typename R>
class shared_future
{
public:
typedef future_state::state state;
shared_future();
~shared_future();
// copy support
shared_future(shared_future const& other);
shared_future& operator=(shared_future const& other);
// move support
shared_future(shared_future && other);
shared_future(unique_future<R> && other);
shared_future& operator=(shared_future && other);
shared_future& operator=(unique_future<R> && other);
void swap(shared_future& other);
// retrieving the value
R get();
// functions to check state, and wait for ready
state get_state() const;
bool is_ready() const;
bool has_exception() const;
bool has_value() const;
// waiting for the result to be ready
void wait() const;
template<typename Duration>
bool timed_wait(Duration const& rel_time) const;
bool timed_wait_until(boost::system_time const& abs_time) const;
};
[section:default_constructor Default Constructor]
shared_future();
[variablelist
[[Effects:] [Constructs an uninitialized future.]]
[[Postconditions:] [[shared_future_is_ready_link `this->is_ready`] returns `false`. [shared_future_get_state_link
`this->get_state()`] returns __uninitialized__.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:get Member function `get()`]
const R& get();
[variablelist
[[Effects:] [If `*this` is associated with an asynchronous result, waits until the result is ready as-if by a call to
__shared_future_wait__, and returns a `const` reference to the result.]]
[[Returns:] [If the result type `R` is a reference, returns the stored reference. If `R` is `void`, there is no return
value. Otherwise, returns a `const` reference to the value stored in the asynchronous result.]]
[[Throws:] [__future_uninitialized__ if `*this` is not associated with an asynchronous result. __thread_interrupted__ if the
result associated with `*this` is not ready at the point of the call, and the current thread is interrupted.]]
[[Notes:] [`get()` is an ['interruption point].]]
]
[endsect]
[section:wait Member function `wait()`]
void wait();
[variablelist
[[Effects:] [If `*this` is associated with an asynchronous result, waits until the result is ready. If the result is not ready on
entry, and the result has a ['wait callback] set, that callback is invoked prior to waiting.]]
[[Throws:] [__future_uninitialized__ if `*this` is not associated with an asynchronous result. __thread_interrupted__ if the result
associated with `*this` is not ready at the point of the call, and the current thread is interrupted. Any exception thrown by the
['wait callback] if such a callback is called.]]
[[Postconditions:] [[shared_future_is_ready_link `this->is_ready()`] returns `true`. [shared_future_get_state_link
`this->get_state()`] returns __ready__.]]
[[Notes:] [`wait()` is an ['interruption point].]]
]
[endsect]
[section:timed_wait_duration Member function `timed_wait()`]
template<typename Duration>
bool timed_wait(Duration const& wait_duration);
[variablelist
[[Effects:] [If `*this` is associated with an asynchronous result, waits until the result is ready, or the time specified by
`wait_duration` has elapsed. If the result is not ready on entry, and the result has a ['wait callback] set, that callback is
invoked prior to waiting.]]
[[Returns:] [`true` if `*this` is associated with an asynchronous result, and that result is ready before the specified time has
elapsed, `false` otherwise.]]
[[Throws:] [__future_uninitialized__ if `*this` is not associated with an asynchronous result. __thread_interrupted__ if the result
associated with `*this` is not ready at the point of the call, and the current thread is interrupted. Any exception thrown by the
['wait callback] if such a callback is called.]]
[[Postconditions:] [If this call returned `true`, then [shared_future_is_ready_link `this->is_ready()`] returns `true` and
[shared_future_get_state_link `this->get_state()`] returns __ready__.]]
[[Notes:] [`timed_wait()` is an ['interruption point]. `Duration` must be a type that meets the Boost.DateTime time duration requirements.]]
]
[endsect]
[section:timed_wait_absolute Member function `timed_wait()`]
bool timed_wait(boost::system_time const& wait_timeout);
[variablelist
[[Effects:] [If `*this` is associated with an asynchronous result, waits until the result is ready, or the time point specified by
`wait_timeout` has passed. If the result is not ready on entry, and the result has a ['wait callback] set, that callback is invoked
prior to waiting.]]
[[Returns:] [`true` if `*this` is associated with an asynchronous result, and that result is ready before the specified time has
passed, `false` otherwise.]]
[[Throws:] [__future_uninitialized__ if `*this` is not associated with an asynchronous result. __thread_interrupted__ if the result
associated with `*this` is not ready at the point of the call, and the current thread is interrupted. Any exception thrown by the
['wait callback] if such a callback is called.]]
[[Postconditions:] [If this call returned `true`, then [shared_future_is_ready_link `this->is_ready()`] returns `true` and
[shared_future_get_state_link `this->get_state()`] returns __ready__.]]
[[Notes:] [`timed_wait()` is an ['interruption point].]]
]
[endsect]
[section:is_ready Member function `is_ready()`]
bool is_ready();
[variablelist
[[Effects:] [Checks to see if the asynchronous result associated with `*this` is set.]]
[[Returns:] [`true` if `*this` is associated with an asynchronous result, and that result is ready for retrieval, `false`
otherwise.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:has_value Member function `has_value()`]
bool has_value();
[variablelist
[[Effects:] [Checks to see if the asynchronous result associated with `*this` is set with a value rather than an exception.]]
[[Returns:] [`true` if `*this` is associated with an asynchronous result, that result is ready for retrieval, and the result is a
stored value, `false` otherwise.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:has_exception Member function `has_exception()`]
bool has_exception();
[variablelist
[[Effects:] [Checks to see if the asynchronous result associated with `*this` is set with an exception rather than a value.]]
[[Returns:] [`true` if `*this` is associated with an asynchronous result, that result is ready for retrieval, and the result is a
stored exception, `false` otherwise.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:get_state Member function `get_state()`]
future_state::state get_state();
[variablelist
[[Effects:] [Determine the state of the asynchronous result associated with `*this`, if any.]]
[[Returns:] [__uninitialized__ if `*this` is not associated with an asynchronous result. __ready__ if the asynchronous result
associated with `*this` is ready for retrieval, __waiting__ otherwise.]]
[[Throws:] [Nothing.]]
]
[endsect]
[endsect]
[section:promise `promise` class template]
template <typename R>
class promise
{
promise(promise & rhs);// = delete;
promise & operator=(promise & rhs);// = delete;
public:
// template <class Allocator> explicit promise(Allocator a);
promise();
~promise();
// Move support
promise(promise && rhs);
promise & operator=(promise&& rhs);
void swap(promise& other);
// Result retrieval
unique_future<R> get_future();
// Set the value
void set_value(R& r);
void set_value(R&& r);
void set_exception(boost::exception_ptr e);
template<typename F>
void set_wait_callback(F f);
};
[section:default_constructor Default Constructor]
promise();
[variablelist
[[Effects:] [Constructs a new __promise__ with no associated result.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:move_constructor Move Constructor]
promise(promise && other);
[variablelist
[[Effects:] [Constructs a new __promise__, and transfers ownership of the result associated with `other` to `*this`, leaving `other`
with no associated result.]]
[[Throws:] [Nothing.]]
[[Notes:] [If the compiler does not support rvalue-references, this is implemented using the boost.thread move emulation.]]
]
[endsect]
[section:move_assignment Move Assignment Operator]
promise& operator=(promise && other);
[variablelist
[[Effects:] [Transfers ownership of the result associated with `other` to `*this`, leaving `other` with no associated result. If there
was already a result associated with `*this`, and that result was not ['ready], sets any futures associated with that result to
['ready] with a __broken_promise__ exception as the result. ]]
[[Throws:] [Nothing.]]
[[Notes:] [If the compiler does not support rvalue-references, this is implemented using the boost.thread move emulation.]]
]
[endsect]
[section:destructor Destructor]
~promise();
[variablelist
[[Effects:] [Destroys `*this`. If there was a result associated with `*this`, and that result is not ['ready], sets any futures
associated with that task to ['ready] with a __broken_promise__ exception as the result.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:get_future Member Function `get_future()`]
unique_future<R> get_future();
[variablelist
[[Effects:] [If `*this` was not associated with a result, allocate storage for a new asynchronous result and associate it with
`*this`. Returns a __unique_future__ associated with the result associated with `*this`. ]]
[[Throws:] [__future_already_retrieved__ if the future associated with the task has already been retrieved. `std::bad_alloc` if any
memory necessary could not be allocated.]]
]
[endsect]
[section:set_value Member Function `set_value()`]
void set_value(R&& r);
void set_value(const R& r);
void promise<R&>::set_value(R& r);
void promise<void>::set_value();
[variablelist
[[Effects:] [If `*this` was not associated with a result, allocate storage for a new asynchronous result and associate it with
`*this`. Store the value `r` in the asynchronous result associated with `*this`. Any threads blocked waiting for the asynchronous
result are woken.]]
[[Postconditions:] [All futures waiting on the asynchronous result are ['ready] and __unique_future_has_value__ or
__shared_future_has_value__ for those futures shall return `true`.]]
[[Throws:] [__promise_already_satisfied__ if the result associated with `*this` is already ['ready]. `std::bad_alloc` if the memory
required for storage of the result cannot be allocated. Any exception thrown by the copy or move-constructor of `R`.]]
]
[endsect]
[section:set_exception Member Function `set_exception()`]
void set_exception(boost::exception_ptr e);
[variablelist
[[Effects:] [If `*this` was not associated with a result, allocate storage for a new asynchronous result and associate it with
`*this`. Store the exception `e` in the asynchronous result associated with `*this`. Any threads blocked waiting for the asynchronous
result are woken.]]
[[Postconditions:] [All futures waiting on the asynchronous result are ['ready] and __unique_future_has_exception__ or
__shared_future_has_exception__ for those futures shall return `true`.]]
[[Throws:] [__promise_already_satisfied__ if the result associated with `*this` is already ['ready]. `std::bad_alloc` if the memory
required for storage of the result cannot be allocated.]]
]
[endsect]
[section:set_wait_callback Member Function `set_wait_callback()`]
template<typename F>
void set_wait_callback(F f);
[variablelist
[[Preconditions:] [The expression `f(t)` where `t` is a lvalue of type __packaged_task__ shall be well-formed. Invoking a copy of
`f` shall have the same effect as invoking `f`]]
[[Effects:] [Store a copy of `f` with the asynchronous result associated with `*this` as a ['wait callback]. This will replace any
existing wait callback store alongside that result. If a thread subsequently calls one of the wait functions on a __unique_future__
or __shared_future__ associated with this result, and the result is not ['ready], `f(*this)` shall be invoked.]]
[[Throws:] [`std::bad_alloc` if memory cannot be allocated for the required storage.]]
]
[endsect]
[endsect]
[section:packaged_task `packaged_task` class template]
template<typename R>
class packaged_task
{
packaged_task(packaged_task&);// = delete;
packaged_task& operator=(packaged_task&);// = delete;
public:
// construction and destruction
template <class F>
explicit packaged_task(F const& f);
explicit packaged_task(R(*f)());
template <class F>
explicit packaged_task(F&& f);
// template <class F, class Allocator>
// explicit packaged_task(F const& f, Allocator a);
// template <class F, class Allocator>
// explicit packaged_task(F&& f, Allocator a);
~packaged_task()
{}
// move support
packaged_task(packaged_task&& other);
packaged_task& operator=(packaged_task&& other);
void swap(packaged_task& other);
// result retrieval
unique_future<R> get_future();
// execution
void operator()();
template<typename F>
void set_wait_callback(F f);
};
[section:task_constructor Task Constructor]
template<typename F>
packaged_task(F const &f);
packaged_task(R(*f)());
template<typename F>
packaged_task(F&&f);
[variablelist
[[Preconditions:] [`f()` is a valid expression with a return type convertible to `R`. Invoking a copy of `f` shall behave the same
as invoking `f`.]]
[[Effects:] [Constructs a new __packaged_task__ with a copy of `f` stored as the associated task.]]
[[Throws:] [Any exceptions thrown by the copy (or move) constructor of `f`. `std::bad_alloc` if memory for the internal data
structures could not be allocated.]]
]
[endsect]
[section:move_constructor Move Constructor]
packaged_task(packaged_task && other);
[variablelist
[[Effects:] [Constructs a new __packaged_task__, and transfers ownership of the task associated with `other` to `*this`, leaving `other`
with no associated task.]]
[[Throws:] [Nothing.]]
[[Notes:] [If the compiler does not support rvalue-references, this is implemented using the boost.thread move emulation.]]
]
[endsect]
[section:move_assignment Move Assignment Operator]
packaged_task& operator=(packaged_task && other);
[variablelist
[[Effects:] [Transfers ownership of the task associated with `other` to `*this`, leaving `other` with no associated task. If there
was already a task associated with `*this`, and that task has not been invoked, sets any futures associated with that task to
['ready] with a __broken_promise__ exception as the result. ]]
[[Throws:] [Nothing.]]
[[Notes:] [If the compiler does not support rvalue-references, this is implemented using the boost.thread move emulation.]]
]
[endsect]
[section:destructor Destructor]
~packaged_task();
[variablelist
[[Effects:] [Destroys `*this`. If there was a task associated with `*this`, and that task has not been invoked, sets any futures
associated with that task to ['ready] with a __broken_promise__ exception as the result.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:get_future Member Function `get_future()`]
unique_future<R> get_future();
[variablelist
[[Effects:] [Returns a __unique_future__ associated with the result of the task associated with `*this`. ]]
[[Throws:] [__task_moved__ if ownership of the task associated with `*this` has been moved to another instance of
__packaged_task__. __future_already_retrieved__ if the future associated with the task has already been retrieved.]]
]
[endsect]
[section:call_operator Member Function `operator()()`]
void operator()();
[variablelist
[[Effects:] [Invoke the task associated with `*this` and store the result in the corresponding future. If the task returns normally,
the return value is stored as the asynchronous result, otherwise the exception thrown is stored. Any threads blocked waiting for the
asynchronous result associated with this task are woken.]]
[[Postconditions:] [All futures waiting on the asynchronous result are ['ready]]]
[[Throws:] [__task_moved__ if ownership of the task associated with `*this` has been moved to another instance of
__packaged_task__. __task_already_started__ if the task has already been invoked.]]
]
[endsect]
[section:set_wait_callback Member Function `set_wait_callback()`]
template<typename F>
void set_wait_callback(F f);
[variablelist
[[Preconditions:] [The expression `f(t)` where `t` is a lvalue of type __packaged_task__ shall be well-formed. Invoking a copy of
`f` shall have the same effect as invoking `f`]]
[[Effects:] [Store a copy of `f` with the task associated with `*this` as a ['wait callback]. This will replace any existing wait
callback store alongside that task. If a thread subsequently calls one of the wait functions on a __unique_future__ or
__shared_future__ associated with this task, and the result of the task is not ['ready], `f(*this)` shall be invoked.]]
[[Throws:] [__task_moved__ if ownership of the task associated with `*this` has been moved to another instance of
__packaged_task__.]]
]
[endsect]
[endsect]
[section:wait_for_any Non-member function `wait_for_any()`]
template<typename Iterator>
Iterator wait_for_any(Iterator begin,Iterator end);
template<typename F1,typename F2>
unsigned wait_for_any(F1& f1,F2& f2);
template<typename F1,typename F2,typename F3>
unsigned wait_for_any(F1& f1,F2& f2,F3& f3);
template<typename F1,typename F2,typename F3,typename F4>
unsigned wait_for_any(F1& f1,F2& f2,F3& f3,F4& f4);
template<typename F1,typename F2,typename F3,typename F4,typename F5>
unsigned wait_for_any(F1& f1,F2& f2,F3& f3,F4& f4,F5& f5);
[variablelist
[[Preconditions:] [The types `Fn` shall be specializations of
__unique_future__ or __shared_future__, and `Iterator` shall be a
forward iterator with a `value_type` which is a specialization of
__unique_future__ or __shared_future__.]]
[[Effects:] [Waits until at least one of the specified futures is ['ready].]]
[[Returns:] [The range-based overload returns an `Iterator` identifying the first future in the range that was detected as
['ready]. The remaining overloads return the zero-based index of the first future that was detected as ['ready] (first parameter =>
0, second parameter => 1, etc.).]]
[[Throws:] [__thread_interrupted__ if the current thread is interrupted. Any exception thrown by the ['wait callback] associated
with any of the futures being waited for. `std::bad_alloc` if memory could not be allocated for the internal wait structures.]]
[[Notes:] [`wait_for_any()` is an ['interruption point].]]
]
[endsect]
[section:wait_for_all Non-member function `wait_for_all()`]
template<typename Iterator>
void wait_for_all(Iterator begin,Iterator end);
template<typename F1,typename F2>
void wait_for_all(F1& f1,F2& f2);
template<typename F1,typename F2,typename F3>
void wait_for_all(F1& f1,F2& f2,F3& f3);
template<typename F1,typename F2,typename F3,typename F4>
void wait_for_all(F1& f1,F2& f2,F3& f3,F4& f4);
template<typename F1,typename F2,typename F3,typename F4,typename F5>
void wait_for_all(F1& f1,F2& f2,F3& f3,F4& f4,F5& f5);
[variablelist
[[Preconditions:] [The types `Fn` shall be specializations of
__unique_future__ or __shared_future__, and `Iterator` shall be a
forward iterator with a `value_type` which is a specialization of
__unique_future__ or __shared_future__.]]
[[Effects:] [Waits until all of the specified futures are ['ready].]]
[[Throws:] [Any exceptions thrown by a call to `wait()` on the specified futures.]]
[[Notes:] [`wait_for_all()` is an ['interruption point].]]
]
[endsect]
[endsect]

187
doc/futures.qbk Executable file
View File

@@ -0,0 +1,187 @@
[/
(C) Copyright 2008-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).
]
[section:futures Futures]
[template future_state_link[link_text] [link thread.synchronization.futures.reference.future_state [link_text]]]
[def __uninitialized__ [future_state_link `boost::future_state::uninitialized`]]
[def __ready__ [future_state_link `boost::future_state::ready`]]
[def __waiting__ [future_state_link `boost::future_state::waiting`]]
[def __future_uninitialized__ `boost::future_uninitialized`]
[def __broken_promise__ `boost::broken_promise`]
[def __future_already_retrieved__ `boost::future_already_retrieved`]
[def __task_moved__ `boost::task_moved`]
[def __task_already_started__ `boost::task_already_started`]
[def __promise_already_satisfied__ `boost::promise_already_satisfied`]
[def __thread_interrupted__ `boost::thread_interrupted`]
[template unique_future_link[link_text] [link thread.synchronization.futures.reference.unique_future [link_text]]]
[def __unique_future__ [unique_future_link `boost::unique_future`]]
[template unique_future_get_link[link_text] [link thread.synchronization.futures.reference.unique_future.get [link_text]]]
[def __unique_future_get__ [unique_future_get_link `boost::unique_future<R>::get()`]]
[template unique_future_wait_link[link_text] [link thread.synchronization.futures.reference.unique_future.wait [link_text]]]
[def __unique_future_wait__ [unique_future_wait_link `boost::unique_future<R>::wait()`]]
[template unique_future_is_ready_link[link_text] [link thread.synchronization.futures.reference.unique_future.is_ready [link_text]]]
[def __unique_future_is_ready__ [unique_future_is_ready_link `boost::unique_future<R>::is_ready()`]]
[template unique_future_has_value_link[link_text] [link thread.synchronization.futures.reference.unique_future.has_value [link_text]]]
[def __unique_future_has_value__ [unique_future_has_value_link `boost::unique_future<R>::has_value()`]]
[template unique_future_has_exception_link[link_text] [link thread.synchronization.futures.reference.unique_future.has_exception [link_text]]]
[def __unique_future_has_exception__ [unique_future_has_exception_link `boost::unique_future<R>::has_exception()`]]
[template unique_future_get_state_link[link_text] [link thread.synchronization.futures.reference.unique_future.get_state [link_text]]]
[def __unique_future_get_state__ [unique_future_get_state_link `boost::unique_future<R>::get_state()`]]
[template shared_future_link[link_text] [link thread.synchronization.futures.reference.shared_future [link_text]]]
[def __shared_future__ [shared_future_link `boost::shared_future`]]
[template shared_future_get_link[link_text] [link thread.synchronization.futures.reference.shared_future.get [link_text]]]
[def __shared_future_get__ [shared_future_get_link `boost::shared_future<R>::get()`]]
[template shared_future_wait_link[link_text] [link thread.synchronization.futures.reference.shared_future.wait [link_text]]]
[def __shared_future_wait__ [shared_future_wait_link `boost::shared_future<R>::wait()`]]
[template shared_future_is_ready_link[link_text] [link thread.synchronization.futures.reference.shared_future.is_ready [link_text]]]
[def __shared_future_is_ready__ [shared_future_is_ready_link `boost::shared_future<R>::is_ready()`]]
[template shared_future_has_value_link[link_text] [link thread.synchronization.futures.reference.shared_future.has_value [link_text]]]
[def __shared_future_has_value__ [shared_future_has_value_link `boost::shared_future<R>::has_value()`]]
[template shared_future_has_exception_link[link_text] [link thread.synchronization.futures.reference.shared_future.has_exception [link_text]]]
[def __shared_future_has_exception__ [shared_future_has_exception_link `boost::shared_future<R>::has_exception()`]]
[template shared_future_get_state_link[link_text] [link thread.synchronization.futures.reference.shared_future.get_state [link_text]]]
[def __shared_future_get_state__ [shared_future_get_state_link `boost::shared_future<R>::get_state()`]]
[template promise_link[link_text] [link thread.synchronization.futures.reference.promise [link_text]]]
[def __promise__ [promise_link `boost::promise`]]
[template packaged_task_link[link_text] [link thread.synchronization.futures.reference.packaged_task [link_text]]]
[def __packaged_task__ [packaged_task_link `boost::packaged_task`]]
[template wait_for_any_link[link_text] [link thread.synchronization.futures.reference.wait_for_any [link_text]]]
[def __wait_for_any__ [wait_for_any_link `boost::wait_for_any()`]]
[template wait_for_all_link[link_text] [link thread.synchronization.futures.reference.wait_for_all [link_text]]]
[def __wait_for_all__ [wait_for_all_link `boost::wait_for_all()`]]
[section:overview Overview]
The futures library provides a means of handling synchronous future values, whether those values are generated by another thread, or
on a single thread in response to external stimuli, or on-demand.
This is done through the provision of four class templates: __unique_future__ and __shared_future__ which are used to retrieve the
asynchronous results, and __promise__ and __packaged_task__ which are used to generate the asynchronous results.
An instance of __unique_future__ holds the one and only reference to a result. Ownership can be transferred between instances using
the move constructor or move-assignment operator, but at most one instance holds a reference to a given asynchronous result. When
the result is ready, it is returned from __unique_future_get__ by rvalue-reference to allow the result to be moved or copied as
appropriate for the type.
On the other hand, many instances of __shared_future__ may reference the same result. Instances can be freely copied and assigned,
and __shared_future_get__ returns a `const` reference so that multiple calls to __shared_future_get__ are safe. You can move an
instance of __unique_future__ into an instance of __shared_future__, thus transferring ownership of the associated asynchronous
result, but not vice-versa.
You can wait for futures either individually or with one of the __wait_for_any__ and __wait_for_all__ functions.
[endsect]
[section:creating Creating asynchronous values]
You can set the value in a future with either a __promise__ or a __packaged_task__. A __packaged_task__ is a callable object that
wraps a function or callable object. When the packaged task is invoked, it invokes the contained function in turn, and populates a
future with the return value. This is an answer to the perennial question: "how do I return a value from a thread?": package the
function you wish to run as a __packaged_task__ and pass the packaged task to the thread constructor. The future retrieved from the
packaged task can then be used to obtain the return value. If the function throws an exception, that is stored in the future in
place of the return value.
int calculate_the_answer_to_life_the_universe_and_everything()
{
return 42;
}
boost::packaged_task<int> pt(calculate_the_answer_to_life_the_universe_and_everything);
boost::unique_future<int> fi=pt.get_future();
boost::thread task(boost::move(pt)); // launch task on a thread
fi.wait(); // wait for it to finish
assert(fi.is_ready());
assert(fi.has_value());
assert(!fi.has_exception());
assert(fi.get_state()==boost::future_state::ready);
assert(fi.get()==42);
A __promise__ is a bit more low level: it just provides explicit functions to store a value or an exception in the associated
future. A promise can therefore be used where the value may come from more than one possible source, or where a single operation may
produce multiple values.
boost::promise<int> pi;
boost::unique_future<int> fi;
fi=pi.get_future();
pi.set_value(42);
assert(fi.is_ready());
assert(fi.has_value());
assert(!fi.has_exception());
assert(fi.get_state()==boost::future_state::ready);
assert(fi.get()==42);
[endsect]
[section:lazy_futures Wait Callbacks and Lazy Futures]
Both __promise__ and __packaged_task__ support ['wait callbacks] that are invoked when a thread blocks in a call to `wait()` or
`timed_wait()` on a future that is waiting for the result from the __promise__ or __packaged_task__, in the thread that is doing the
waiting. These can be set using the `set_wait_callback()` member function on the __promise__ or __packaged_task__ in question.
This allows ['lazy futures] where the result is not actually computed until it is needed by some thread. In the example below, the
call to `f.get()` invokes the callback `invoke_lazy_task`, which runs the task to set the value. If you remove the call to
`f.get()`, the task is not ever run.
int calculate_the_answer_to_life_the_universe_and_everything()
{
return 42;
}
void invoke_lazy_task(boost::packaged_task<int>& task)
{
try
{
task();
}
catch(boost::task_already_started&)
{}
}
int main()
{
boost::packaged_task<int> task(calculate_the_answer_to_life_the_universe_and_everything);
task.set_wait_callback(invoke_lazy_task);
boost::unique_future<int> f(task.get_future());
assert(f.get()==42);
}
[endsect]
[include future_ref.qbk]
[endsect]

View File

@@ -158,6 +158,7 @@
[include condition_variables.qbk]
[include once.qbk]
[include barrier.qbk]
[include futures.qbk]
[endsect]
[include tss.qbk]

View File

@@ -916,6 +916,13 @@ exits (even if the thread has been interrupted).]]
[[Throws:] [`std::bad_alloc` if memory cannot be allocated for the copy of the function, __thread_resource_error__ if any other
error occurs within the thread library. Any exception thrown whilst copying `func` into internal storage.]]
[[Note:] [This function is *not* called if the thread was terminated
forcefully using platform-specific APIs, or if the thread is
terminated due to a call to `exit()`, `abort()` or
`std::terminate()`. In particular, returning from `main()` is
equivalent to call to `exit()`, so will not call any functions
registered with `at_thread_exit()`]]
]
[endsect]

View File

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

View File

@@ -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();
{

View File

@@ -1,6 +1,6 @@
// Copyright (C) 2001-2003
// William E. Kempf
// (C) Copyright 2008 Anthony Williams
// (C) Copyright 2008-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)
@@ -21,5 +21,6 @@
#include <boost/thread/locks.hpp>
#include <boost/thread/shared_mutex.hpp>
#include <boost/thread/barrier.hpp>
#include <boost/thread/future.hpp>
#endif

View File

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

View File

@@ -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,35 +349,14 @@ 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
namespace this_thread
{
class BOOST_THREAD_DECL disable_interruption
{
disable_interruption(const disable_interruption&);
disable_interruption& operator=(const disable_interruption&);
bool interruption_was_enabled;
friend class restore_interruption;
public:
disable_interruption();
~disable_interruption();
};
class BOOST_THREAD_DECL restore_interruption
{
restore_interruption(const restore_interruption&);
restore_interruption& operator=(const restore_interruption&);
public:
explicit restore_interruption(disable_interruption& d);
~restore_interruption();
};
thread::id BOOST_THREAD_DECL get_id();
void BOOST_THREAD_DECL interruption_point();
@@ -487,83 +476,6 @@ namespace boost
detail::add_thread_exit_function(thread_exit_func);
}
}
class thread_group:
private noncopyable
{
public:
~thread_group()
{
for(std::list<thread*>::iterator it=threads.begin(),end=threads.end();
it!=end;
++it)
{
delete *it;
}
}
template<typename F>
thread* create_thread(F threadfunc)
{
boost::lock_guard<mutex> guard(m);
std::auto_ptr<thread> new_thread(new thread(threadfunc));
threads.push_back(new_thread.get());
return new_thread.release();
}
void add_thread(thread* thrd)
{
if(thrd)
{
boost::lock_guard<mutex> guard(m);
threads.push_back(thrd);
}
}
void remove_thread(thread* thrd)
{
boost::lock_guard<mutex> guard(m);
std::list<thread*>::iterator const it=std::find(threads.begin(),threads.end(),thrd);
if(it!=threads.end())
{
threads.erase(it);
}
}
void join_all()
{
boost::lock_guard<mutex> guard(m);
for(std::list<thread*>::iterator it=threads.begin(),end=threads.end();
it!=end;
++it)
{
(*it)->join();
}
}
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();
}
}
size_t size() const
{
boost::lock_guard<mutex> guard(m);
return threads.size();
}
private:
std::list<thread*> threads;
mutable mutex m;
};
}
#ifdef BOOST_MSVC

View File

@@ -0,0 +1,105 @@
#ifndef BOOST_THREAD_DETAIL_THREAD_GROUP_HPP
#define BOOST_THREAD_DETAIL_THREAD_GROUP_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-9 Anthony Williams
#include <list>
#include <boost/thread/shared_mutex.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/config/abi_prefix.hpp>
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable:4251)
#endif
namespace boost
{
class thread_group:
private noncopyable
{
public:
~thread_group()
{
for(std::list<thread*>::iterator it=threads.begin(),end=threads.end();
it!=end;
++it)
{
delete *it;
}
}
template<typename F>
thread* create_thread(F threadfunc)
{
boost::lock_guard<shared_mutex> guard(m);
std::auto_ptr<thread> new_thread(new thread(threadfunc));
threads.push_back(new_thread.get());
return new_thread.release();
}
void add_thread(thread* thrd)
{
if(thrd)
{
boost::lock_guard<shared_mutex> guard(m);
threads.push_back(thrd);
}
}
void remove_thread(thread* thrd)
{
boost::lock_guard<shared_mutex> guard(m);
std::list<thread*>::iterator const it=std::find(threads.begin(),threads.end(),thrd);
if(it!=threads.end())
{
threads.erase(it);
}
}
void join_all()
{
boost::shared_lock<shared_mutex> guard(m);
for(std::list<thread*>::iterator it=threads.begin(),end=threads.end();
it!=end;
++it)
{
(*it)->join();
}
}
void interrupt_all()
{
boost::shared_lock<shared_mutex> guard(m);
for(std::list<thread*>::iterator it=threads.begin(),end=threads.end();
it!=end;
++it)
{
(*it)->interrupt();
}
}
size_t size() const
{
boost::shared_lock<shared_mutex> guard(m);
return threads.size();
}
private:
std::list<thread*> threads;
mutable shared_mutex m;
};
}
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -0,0 +1,35 @@
#ifndef BOOST_THREAD_DETAIL_THREAD_INTERRUPTION_HPP
#define BOOST_THREAD_DETAIL_THREAD_INTERRUPTION_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-9 Anthony Williams
namespace boost
{
namespace this_thread
{
class BOOST_THREAD_DECL disable_interruption
{
disable_interruption(const disable_interruption&);
disable_interruption& operator=(const disable_interruption&);
bool interruption_was_enabled;
friend class restore_interruption;
public:
disable_interruption();
~disable_interruption();
};
class BOOST_THREAD_DECL restore_interruption
{
restore_interruption(const restore_interruption&);
restore_interruption& operator=(const restore_interruption&);
public:
explicit restore_interruption(disable_interruption& d);
~restore_interruption();
};
}
}
#endif

View File

@@ -1,6 +1,6 @@
// Copyright (C) 2001-2003
// William E. Kempf
// Copyright (C) 2007-8 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)
@@ -24,23 +24,36 @@
namespace boost
{
class BOOST_THREAD_DECL thread_interrupted
class thread_interrupted
{};
class BOOST_THREAD_DECL thread_exception : public std::exception
{
protected:
thread_exception();
thread_exception(int sys_err_code);
class thread_exception:
public std::exception
{
protected:
thread_exception():
m_sys_err(0)
{}
thread_exception(int sys_err_code):
m_sys_err(sys_err_code)
{}
public:
~thread_exception() throw();
public:
~thread_exception() throw()
{}
int native_error() const;
int native_error() const
{
return m_sys_err;
}
private:
int m_sys_err;
};
private:
int m_sys_err;
};
class condition_error:
public std::exception
@@ -53,62 +66,117 @@ private:
};
class BOOST_THREAD_DECL lock_error : public thread_exception
{
public:
lock_error();
lock_error(int sys_err_code);
~lock_error() throw();
class lock_error:
public thread_exception
{
public:
lock_error()
{}
lock_error(int sys_err_code):
thread_exception(sys_err_code)
{}
~lock_error() throw()
{}
virtual const char* what() const throw();
};
virtual const char* what() const throw()
{
return "boost::lock_error";
}
};
class BOOST_THREAD_DECL thread_resource_error : public thread_exception
{
public:
thread_resource_error();
thread_resource_error(int sys_err_code);
~thread_resource_error() throw();
class thread_resource_error:
public thread_exception
{
public:
thread_resource_error()
{}
thread_resource_error(int sys_err_code):
thread_exception(sys_err_code)
{}
~thread_resource_error() throw()
{}
virtual const char* what() const throw();
};
virtual const char* what() const throw()
{
return "boost::thread_resource_error";
}
};
class BOOST_THREAD_DECL unsupported_thread_option : public thread_exception
{
public:
unsupported_thread_option();
unsupported_thread_option(int sys_err_code);
~unsupported_thread_option() throw();
class unsupported_thread_option:
public thread_exception
{
public:
unsupported_thread_option()
{}
unsupported_thread_option(int sys_err_code):
thread_exception(sys_err_code)
{}
~unsupported_thread_option() throw()
{}
virtual const char* what() const throw();
};
virtual const char* what() const throw()
{
return "boost::unsupported_thread_option";
}
};
class BOOST_THREAD_DECL invalid_thread_argument : public thread_exception
{
public:
invalid_thread_argument();
invalid_thread_argument(int sys_err_code);
~invalid_thread_argument() throw();
class invalid_thread_argument:
public thread_exception
{
public:
invalid_thread_argument()
{}
invalid_thread_argument(int sys_err_code):
thread_exception(sys_err_code)
{}
~invalid_thread_argument() throw()
{}
virtual const char* what() const throw();
};
virtual const char* what() const throw()
{
return "boost::invalid_thread_argument";
}
};
class BOOST_THREAD_DECL thread_permission_error : public thread_exception
{
public:
thread_permission_error();
thread_permission_error(int sys_err_code);
~thread_permission_error() throw();
class thread_permission_error:
public thread_exception
{
public:
thread_permission_error()
{}
thread_permission_error(int sys_err_code):
thread_exception(sys_err_code)
{}
~thread_permission_error() throw()
{}
virtual const char* what() const throw();
};
virtual const char* what() const throw()
{
return "boost::thread_permission_error";
}
};
} // namespace boost
#include <boost/config/abi_suffix.hpp>
#endif // BOOST_THREAD_CONFIG_PDM070801_H
// Change log:
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -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)
{}
@@ -260,16 +263,16 @@ namespace boost
}
unique_lock& operator=(unique_lock<Mutex>&& other)
unique_lock& operator=(unique_lock&& other)
{
unique_lock temp(other);
unique_lock temp(other.move());
swap(temp);
return *this;
}
unique_lock& operator=(upgrade_lock<Mutex>&& other)
{
unique_lock temp(other);
unique_lock temp(other.move());
swap(temp);
return *this;
}
@@ -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)
{
@@ -772,7 +783,7 @@ namespace boost
other.is_locked=false;
if(is_locked)
{
m.unlock_upgrade_and_lock();
m->unlock_upgrade_and_lock();
}
}
#else
@@ -864,6 +875,28 @@ namespace boost
try_lock_wrapper(Mutex& m_,try_to_lock_t):
base(m_,try_to_lock)
{}
#ifdef BOOST_HAS_RVALUE_REFS
try_lock_wrapper(try_lock_wrapper&& other):
base(other.move())
{}
try_lock_wrapper&& move()
{
return static_cast<try_lock_wrapper&&>(*this);
}
try_lock_wrapper& operator=(try_lock_wrapper<Mutex>&& other)
{
try_lock_wrapper temp(other.move());
swap(temp);
return *this;
}
void swap(try_lock_wrapper&& other)
{
base::swap(other);
}
#else
try_lock_wrapper(detail::thread_move_t<try_lock_wrapper<Mutex> > other):
base(detail::thread_move_t<base>(*other))
{}
@@ -885,12 +918,6 @@ namespace boost
return *this;
}
#ifdef BOOST_HAS_RVALUE_REFS
void swap(try_lock_wrapper&& other)
{
base::swap(other);
}
#else
void swap(try_lock_wrapper& other)
{
base::swap(other);
@@ -900,7 +927,6 @@ namespace boost
base::swap(*other);
}
#endif
void lock()
{
base::lock();

View File

@@ -10,8 +10,8 @@
#include <boost/assert.hpp>
#include <boost/static_assert.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/condition_variable.hpp>
#include <boost/thread/detail/thread_interruption.hpp>
#include <boost/config/abi_prefix.hpp>

View File

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

View File

@@ -20,6 +20,8 @@
#endif
#include <boost/thread/detail/thread.hpp>
#include <boost/thread/detail/thread_interruption.hpp>
#include <boost/thread/detail/thread_group.hpp>
#endif

View File

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

View File

@@ -1 +0,0 @@
boost_module(thread DEPENDS date_time bind optional range)

View File

@@ -1,21 +0,0 @@
#
# 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
)

View File

@@ -1,124 +0,0 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// 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/exceptions.hpp>
#include <cstring>
#include <string>
namespace boost {
thread_exception::thread_exception()
: m_sys_err(0)
{
}
thread_exception::thread_exception(int sys_err_code)
: m_sys_err(sys_err_code)
{
}
thread_exception::~thread_exception() throw()
{
}
int thread_exception::native_error() const
{
return m_sys_err;
}
lock_error::lock_error()
{
}
lock_error::lock_error(int sys_err_code)
: thread_exception(sys_err_code)
{
}
lock_error::~lock_error() throw()
{
}
const char* lock_error::what() const throw()
{
return "boost::lock_error";
}
thread_resource_error::thread_resource_error()
{
}
thread_resource_error::thread_resource_error(int sys_err_code)
: thread_exception(sys_err_code)
{
}
thread_resource_error::~thread_resource_error() throw()
{
}
const char* thread_resource_error::what() const throw()
{
return "boost::thread_resource_error";
}
unsupported_thread_option::unsupported_thread_option()
{
}
unsupported_thread_option::unsupported_thread_option(int sys_err_code)
: thread_exception(sys_err_code)
{
}
unsupported_thread_option::~unsupported_thread_option() throw()
{
}
const char* unsupported_thread_option::what() const throw()
{
return "boost::unsupported_thread_option";
}
invalid_thread_argument::invalid_thread_argument()
{
}
invalid_thread_argument::invalid_thread_argument(int sys_err_code)
: thread_exception(sys_err_code)
{
}
invalid_thread_argument::~invalid_thread_argument() throw()
{
}
const char* invalid_thread_argument::what() const throw()
{
return "boost::invalid_thread_argument";
}
thread_permission_error::thread_permission_error()
{
}
thread_permission_error::thread_permission_error(int sys_err_code)
: thread_exception(sys_err_code)
{
}
thread_permission_error::~thread_permission_error() throw()
{
}
const char* thread_permission_error::what() const throw()
{
return "boost::thread_permission_error";
}
} // namespace boost

0
src/pthread/once.cpp Executable file → Normal file
View File

View File

@@ -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();
@@ -390,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;
@@ -552,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 &current_node->second;
}
}
return NULL;
@@ -573,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();
// }
}

View File

@@ -1,124 +0,0 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// 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/exceptions.hpp>
#include <cstring>
#include <string>
namespace boost {
thread_exception::thread_exception()
: m_sys_err(0)
{
}
thread_exception::thread_exception(int sys_err_code)
: m_sys_err(sys_err_code)
{
}
thread_exception::~thread_exception() throw()
{
}
int thread_exception::native_error() const
{
return m_sys_err;
}
lock_error::lock_error()
{
}
lock_error::lock_error(int sys_err_code)
: thread_exception(sys_err_code)
{
}
lock_error::~lock_error() throw()
{
}
const char* lock_error::what() const throw()
{
return "boost::lock_error";
}
thread_resource_error::thread_resource_error()
{
}
thread_resource_error::thread_resource_error(int sys_err_code)
: thread_exception(sys_err_code)
{
}
thread_resource_error::~thread_resource_error() throw()
{
}
const char* thread_resource_error::what() const throw()
{
return "boost::thread_resource_error";
}
unsupported_thread_option::unsupported_thread_option()
{
}
unsupported_thread_option::unsupported_thread_option(int sys_err_code)
: thread_exception(sys_err_code)
{
}
unsupported_thread_option::~unsupported_thread_option() throw()
{
}
const char* unsupported_thread_option::what() const throw()
{
return "boost::unsupported_thread_option";
}
invalid_thread_argument::invalid_thread_argument()
{
}
invalid_thread_argument::invalid_thread_argument(int sys_err_code)
: thread_exception(sys_err_code)
{
}
invalid_thread_argument::~invalid_thread_argument() throw()
{
}
const char* invalid_thread_argument::what() const throw()
{
return "boost::invalid_thread_argument";
}
thread_permission_error::thread_permission_error()
{
}
thread_permission_error::thread_permission_error(int sys_err_code)
: thread_exception(sys_err_code)
{
}
thread_permission_error::~thread_permission_error() throw()
{
}
const char* thread_permission_error::what() const throw()
{
return "boost::thread_permission_error";
}
} // namespace boost

View File

@@ -561,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);
}

View File

@@ -1,39 +0,0 @@
#
# 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)

View File

@@ -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 ]
@@ -55,6 +57,7 @@ rule thread-run ( sources )
[ thread-run test_shared_mutex_timed_locks.cpp ]
[ thread-run test_lock_concept.cpp ]
[ thread-run test_generic_locks.cpp ]
[ thread-run test_futures.cpp ]
[ compile-fail no_implicit_move_from_lvalue_thread.cpp ]
[ compile-fail no_implicit_assign_from_lvalue_thread.cpp ]
;

1218
test/test_futures.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

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

View 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;
}

View 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;
}

View File

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