|
Boost-Commit : |
Subject: [Boost-commit] svn:boost r50462 - sandbox/interthreads/libs/interthreads/doc
From: vicente.botet_at_[hidden]
Date: 2009-01-04 13:01:49
Author: viboes
Date: 2009-01-04 13:01:47 EST (Sun, 04 Jan 2009)
New Revision: 50462
URL: http://svn.boost.org/trac/boost/changeset/50462
Log:
interthreads version 0.2
Adding threader/joiner
Adding Asynchronous Executors fmk
Text files modified:
sandbox/interthreads/libs/interthreads/doc/Jamfile.v2 | 3
sandbox/interthreads/libs/interthreads/doc/case_studies.qbk | 2
sandbox/interthreads/libs/interthreads/doc/changes.qbk | 30
sandbox/interthreads/libs/interthreads/doc/getting_started.qbk | 41 +
sandbox/interthreads/libs/interthreads/doc/installation.qbk | 10
sandbox/interthreads/libs/interthreads/doc/interthreads.qbk | 3
sandbox/interthreads/libs/interthreads/doc/introduction.qbk | 523 ++++++++++++++++
sandbox/interthreads/libs/interthreads/doc/overview.qbk | 15
sandbox/interthreads/libs/interthreads/doc/reference.qbk | 1240 ++++++++++++++++++++++++++++++++++++---
sandbox/interthreads/libs/interthreads/doc/tutorial.qbk | 67 +
10 files changed, 1770 insertions(+), 164 deletions(-)
Modified: sandbox/interthreads/libs/interthreads/doc/Jamfile.v2
==============================================================================
--- sandbox/interthreads/libs/interthreads/doc/Jamfile.v2 (original)
+++ sandbox/interthreads/libs/interthreads/doc/Jamfile.v2 2009-01-04 13:01:47 EST (Sun, 04 Jan 2009)
@@ -4,7 +4,8 @@
# 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)
-path-constant boost-images : ../../../../doc/src/images ;
+#path-constant boost-images : ../../../../doc/src/images ;
+import quickbook ;
xml interthreads : interthreads.qbk ;
Modified: sandbox/interthreads/libs/interthreads/doc/case_studies.qbk
==============================================================================
--- sandbox/interthreads/libs/interthreads/doc/case_studies.qbk (original)
+++ sandbox/interthreads/libs/interthreads/doc/case_studies.qbk 2009-01-04 13:01:47 EST (Sun, 04 Jan 2009)
@@ -586,4 +586,4 @@
[endsect]
-[endsect]
+[endsect]
\ No newline at end of file
Modified: sandbox/interthreads/libs/interthreads/doc/changes.qbk
==============================================================================
--- sandbox/interthreads/libs/interthreads/doc/changes.qbk (original)
+++ sandbox/interthreads/libs/interthreads/doc/changes.qbk 2009-01-04 13:01:47 EST (Sun, 04 Jan 2009)
@@ -7,13 +7,37 @@
[section:changes Appendix A: History]
-[heading [*Version 0.1, Novembre 30, 2008] ['Announcement of Interthreads]
+[heading [*Version 0.2, December 07, 2008] ['Movable thread tuples, Threader and test on more toolsets]]
+
+[*Features:]
+
+* Make movable thread_tuple_once and thread_group_once
+* Threader/joiner classes
+
+[*Toolsets:]
+
+* Tested with static and shared lib.
+* Tested on Linux gcc 3.4.6.
+* Tested on Linux gcc 4.1.2.
+* Modification helping Windows.
+
+[*Bugs:]
+
+* basic_keep_alive example do not link.
+
+[heading [*Version 0.1, November 30, 2008] ['Announcement of Interthreads]]
+
+[*Features:]
-[*Features:]
* thread setup/cleanup decorator,
* thread specific shared pointer,
* thread keep alive mechanism,
* thread tuples, set_once synchonizer, thread_tuple_once and thread_group_once.
+
+[heading [*Bugs:]]
-[endsect]
+[*v0.1#1: basic_keep_alive example do not link.]
+
+
+[endsect]
Modified: sandbox/interthreads/libs/interthreads/doc/getting_started.qbk
==============================================================================
--- sandbox/interthreads/libs/interthreads/doc/getting_started.qbk (original)
+++ sandbox/interthreads/libs/interthreads/doc/getting_started.qbk 2009-01-04 13:01:47 EST (Sun, 04 Jan 2009)
@@ -55,6 +55,12 @@
Bye, Bye!
]
+
+ int main() {
+ bith::wait_for_all(basic_threader_decorator, my_thread);
+ return 0;
+ }
+
[endsect]
[/==========================]
@@ -138,6 +144,25 @@
]
+ struct mono_thread_id_out {
+ template<typename T>
+ void operator()(T& t) const {
+ std::cout << "thread::id=" << t.get_id()
+ << " mono_thread_id=" << mono_thread_id::id(t.get_id())
+ << std::endl;
+ }
+ };
+
+ int main() {
+ bith::result_of::fork_all<basic_threader_decorator, my_thread, my_thread> handles =
+ bith::fork_all(basic_threader_decorator, my_thread, my_thread);
+ sleep(2);
+ boost::fusion::for_each(handles, mono_thread_id_out());
+ bith.join_all();
+ return 0;
+ }
+
+
[endsect]
[/=======================]
@@ -180,6 +205,11 @@
[pre
]
+ int main() {
+ bith::wait_for_all(basic_threader_decorator, my_thread, my_thread);
+ return 0;
+ }
+
[endsect]
[/==========================]
@@ -188,7 +218,8 @@
This example shows how to launch several algorithms and wait only for the more efficient.
- #include <boost/interthreads/thread_tuple.hpp>
+ #include <boost/interthreads/thread_tuple_once.hpp>
+ #include <boost/interthreads/thread_and_join.hpp>
#include <boost/thread.hpp>
#include <iostream>
@@ -205,8 +236,7 @@
}
int main() {
- unsigned res = bith::thread_and_join_first_then_interrupt(my_thread1, my_thread2)
- );
+ unsigned res = bith::conc_join_any(basic_threader(), my_thread1, my_thread2);
std::cout << "Algotithm " << res+1 << "finished the first" << std::endl;
return 0;
}
@@ -216,6 +246,11 @@
[pre
]
+ int main() {
+ std::pair<unsigned,void> res = bith::wait_for_any(launcher, my_thread, my_thread);
+ return 0;
+ }
+
[endsect]
[endsect]
Modified: sandbox/interthreads/libs/interthreads/doc/installation.qbk
==============================================================================
--- sandbox/interthreads/libs/interthreads/doc/installation.qbk (original)
+++ sandbox/interthreads/libs/interthreads/doc/installation.qbk 2009-01-04 13:01:47 EST (Sun, 04 Jan 2009)
@@ -14,8 +14,10 @@
[heading Getting Boost.InterThreads]
[/=================================]
-You can get __Boost_InterThreads__ by downloading [^interthreads.zip] from
-[@http://www.boost-consulting.com/vault/index.php?directory=Concurrent%20Programming Vault]
+You can get the last stable release of __Boost_InterThreads__ by downloading [^interthreads.zip] from the
+[@http://www.boost-consulting.com/vault/index.php?directory=Concurrent%20Programming Boost Vault]
+
+You can also access the latest (unstable?) state from the [@https://svn.boost.org/svn/boost/sandbox/interthreads Boost Sandbox].
[/==================================]
[heading Building Boost.InterThreads]
@@ -69,8 +71,10 @@
Currently, __Boost_InterThreads__ has been tested in the following compilers/platforms:
* GCC 3.4.4 Cygwin
+* GCC 3.4.6 Linux
* GCC 4.3.2 Cygwin
+* GCC 4.1.2 Linux
[note Please send any questions, comments and bug reports to boost <at> lists <dot> boost <dot> org.]
-[endsect]
+[endsect]
\ No newline at end of file
Modified: sandbox/interthreads/libs/interthreads/doc/interthreads.qbk
==============================================================================
--- sandbox/interthreads/libs/interthreads/doc/interthreads.qbk (original)
+++ sandbox/interthreads/libs/interthreads/doc/interthreads.qbk 2009-01-04 13:01:47 EST (Sun, 04 Jan 2009)
@@ -181,6 +181,3 @@
[include case_studies.qbk]
[include appendices.qbk]
-
-
-
Modified: sandbox/interthreads/libs/interthreads/doc/introduction.qbk
==============================================================================
--- sandbox/interthreads/libs/interthreads/doc/introduction.qbk (original)
+++ sandbox/interthreads/libs/interthreads/doc/introduction.qbk 2009-01-04 13:01:47 EST (Sun, 04 Jan 2009)
@@ -4,10 +4,500 @@
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt).
]
+[/=============================================================================]
+[/============================]
[section:motivation Motivation]
+[/============================]
-[section:decorator_motivation Decorators]
+[section Asynchronous Executors and Asynchronous Completion Token Handles]
+[/=======================================================================]
+
+In [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1883.pdf N1833 - Preliminary Threading Library Proposal for TR2]
+Kevlin Henney introduce the concept of threader and a function thread that evaluate a function asynchronously and returns a joiner handle.
+
+In [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2185.html N2185 - Proposed Text for Parallel Task Execution]
+Peter Dimov introduce a fork function able to evaluate a function asynchronously and
+returns a future handle.
+
+In [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2276.html N2276 - Thread Pools and Futures]
+Anthony William introduce launch_in_thread and launch_in_pool function templates which
+evaluate a function asynchronously either in a specific thread or a thread pool and
+returns a unique_future handle.
+
+In [@http://www.boostpro.com/vault/index.php?action=downloadfile&filename=boost-threadpool.3.tar.gz&directory=Concurrent%20Programming& Boost.ThreadPool]
+Oliver Kowalke propose a complete implementation of a thread pool with a submit function
+which evaluate a function asynchronously and returns a task handle.
+
+Behind all these proposal there is a concept of asynchronous executor, fork-like function and
+the asynchronous completion token handle.
+
+[table fork Parameters
+ [
+ [[*Proposal]] [[*executor]] [[*fork-like]] [[*ACT handle]]
+ ]
+ [
+ [Boost.Thread] [??] [thread constructor] [thread]
+ ]
+ [
+ [Boost.ThreadPool] [tp::pool] [submit] [tp::task]
+ ]
+ [
+ [N2276] [thread] [launch_in_thread] [unique_future<T>]
+ ]
+ [
+ [N2276] [thread_pool] [launch_in_pool] [unique_future<T>]
+ ]
+ [
+ [N2185] [??] [fork] [future<T>]
+ ]
+ [
+ [N1833] [threader] [thread] [joiner<T>]
+ ]
+]
+
+The asynchronous completion token models can follows two interfaces, the thread interface and
+the unique_future interface. Some asynchronous completion token handle allows to recover the result of the evaluation of
+the function, other allows to manage the underlying thread of execution.
+
+It seems natural to make a generic fork function that will evaluate a function asynchronously
+with respect to the calling thread and returns an ACT handle. The following metafunction
+associated an ACT handle to a asynchronous executor.
+
+ template <typename AE, typename T>
+ struct asynchronous_completion_token {
+ typedef typename AE::handle<T>::type type;
+ };
+
+The result of forking a nullary function by an asynchronous executor is given by the metafunction result_of::fork<AE,F>
+
+ namespace result_of {
+ template <typename AE,typename F>
+ struct fork {
+ typedef typename asynchronous_completion_token<AE,
+ typename result_of<F()>::type>::type type;
+ };
+ }
+
+The default implementation of fork delegates on fork asynchronous executor function.
+
+ template< typename AE, typename F >
+ result_of::fork<AE, F>::type fork( AE& ae, F fn ) {
+ return ae.fork(fn);
+ }
+
+Forking n-ary functions relies on the nullary version and bind.
+
+ template< typename AE, typename F, typename A1, ..., typename An >
+ typename asynchronous_completion_token<AE,
+ typename result_of<F(A1,..., An)>::type >::type
+ fork( AE& ae, F fn, A1 a1, ..., An an ) {
+ return launcher.fork( bind( fn, a1, ..., an ) );
+ }
+
+We can define a basic_threader which just returns a new thread as follows:
+
+ class basic_threader {
+ public:
+ template <typename T>
+ struct handle {
+ typedef boost::thread type;
+ };
+
+ template <typename F>
+ boost::thread fork(F f) {
+ thread th(f);
+ return boost::move(th);
+ }
+ };
+
+The library includes a launcher class that creates a thread and returns a unique_future when forking.
+
+ class launcher {
+ public:
+ template <typename T>
+ struct handle {
+ typedef unique_future<T> type;
+ };
+ template <typename F>
+ unique_future<typename result_of<F()>::type>
+ fork(F f) {
+ typedef typename result_of<F()>::type result_type;
+ packaged_task<result_type> tsk(f);
+ unique_future<result_type> res = tsk.get_future();
+ thread th(boost::move(tsk));
+ return res;
+ }
+ };
+
+
+Given the sequential example:
+
+ double f( double a, int n )
+ {
+ double r = 0.0;
+
+ for( int i = 1; i <= n; ++i )
+ {
+ double x = 1.0 / i;
+ r += std::pow( x, a );
+ }
+
+ return r;
+ }
+
+ int main()
+ {
+ double m1 = f( 1.0, 1000000 );
+ double m2 = f( 1.0, 5000000 );
+ double m3 = f( 2.2, 1000000 );
+ double m4 = f( 2.2, 5000000 );
+
+ std::cout << m2 - m1 + m3 - m4 << std::endl;
+ }
+
+this library allows a programmer to switch to parallel execution as follows:
+
+ int main()
+ {
+ launcher l;
+ boost::unique_future<double> fm1 = bith::fork( l, f, 1.0, 1000000 );
+ boost::unique_future<double> fm2 = bith::fork( l, f, 1.0, 5000000 );
+ boost::unique_future<double> fm3 = bith::fork( l, f, 2.2, 1000000 );
+ boost::unique_future<double> fm4 = bith::fork( l, f, 2.2, 5000000 );
+
+ std::cout << fm2.get() - fm1.get() + fm3.get() - fm4.get() << std::endl;
+ }
+
+
+The library include also a threader class based on the Kevlin proposal:
+
+ class threader {
+ public:
+ template <typename T>
+ struct handle {
+ typedef joiner<T> type;
+ };
+ template <typename F>
+ joiner<typename result_of<F()>::type>
+ fork(F f) {
+ typedef typename result_of<F()>::type result_type;
+ return joiner<result_type>(f);
+ }
+
+ };
+
+The question now is how we can adapt it to an existing asynchronous executor such as
+the Boost.ThreadPool library. We need to specialize the template class
+asynchronous_completion_token
+
+ template <typename Channel, typename T>
+ struct asynchronous_completion_token<boost::tp::pool<Channel>,T> {
+ typedef boost::tp::task<T> type;
+ };
+
+and function fork function.
+
+ template< typename Channel, typename F >
+ result_of::fork<boost::tp::pool<Channel>, F>::type
+ fork<boost::tp::pool<Channel>,F>( boost::tp::pool<Channel>& ae, F fn ) {
+ return ae.submit(fn);
+ }
+
+Note that the single fork function that needs specialization is the one taking a nullary
+function as parameter.
+
+We can write the preceding main function in a more generic way
+
+ template < typename AE>
+ void do(AE& ae)
+ {
+ typedef bith::result_of::fork<AE, f, tuple<double, int> >::type auto_type;
+ auto_type fm1 = bith::fork(ae, f, 1.0, 1000000 );
+ auto_type fm2 = bith::fork(ae, f, 1.0, 5000000 );
+ auto_type fm3 = bith::fork(ae, f, 2.2, 1000000 );
+ auto_type fm4 = bith::fork(ae, f, 2.2, 5000000 );
+
+ std::cout << fm2.get() - fm1.get() + fm3.get() - fm4.get() << std::endl;
+ }
+
+ int main()
+ {
+ launcher ae;
+ do(ae);
+ }
+
+and we can switch from using the launcher or the tp::pool just by changing one line
+
+ int main()
+ {
+ boost::tp::pool<> ae(boost::tp::poolsize(6))
+ do(ae);
+ }
+
+The library allows also to fork several functions at the same time
+
+ result_of::fork_all<AE, f, g, h>::type handles = bith::fork_all(ae, f, g, h);
+ std::cout << get<1>(res).get() - get<0>(res).get() + get<2>(res).get() << std::endl;
+
+
+The result of the fork_all operation is a fusion tuple of asynchronous completion token handles.
+The user can apply any fusion algorithm on this tuple as for example
+
+ bool b = fusion::none(handles, fct::interruption_requested());
+
+The asynchronous completion token models follows two interfaces, the thread interface and the
+unique_future interface.
+
+To make common tasks easier the library provide some functors in the name space fct:
+for the thread interface as
+
+* fct::join
+* fct::join_until
+* fct::join_for
+* fct::detach
+* fct::interrupt
+* fct::interrupt_requested
+
+and for the future operations as
+
+* fct::get
+* fct::wait
+* fct::wait_until
+* fct::wait_for
+* fct::is_ready
+* fct::has_value
+* fct::has_exception
+
+Here is an example for get:
+
+ namespace fct {
+ struct get {
+ template<typename ACT>
+ typename ACT::result_type operator()(ACT& t) const {
+ return t.get();
+ }
+ };
+ }
+
+In addition the library provides some non member functions that are the result of applying a
+these functior to the tuple using a fusion algorithm:
+
+* join_all
+* join_all_until
+* join_all_for
+* detach_all
+* interrupt_all
+* interrupt_requested_on_all
+
+* get_all
+* wait_all
+* wait_all_until
+* wait_all_for
+* are_all_ready
+* have_all_value
+* have_all_exception
+
+Next follows how get_all is defined.
+
+ template <typename MovableTuple>
+ typename result_of::get_all<MovableTuple>::type
+ get_all(Sequence& t) {
+ return fusion::transform(t, fct::get());
+ }
+
+The library defines in a systematic way the result_of of a function as a metafunction
+having the same name as the function on the namespace result_of, as the Boost.Fusion library
+does.
+
+ namespace result_of {
+ template <typename Sequence>
+ struct get_all {
+ typedef typename fusion::result_of::transform<Sequence, fct::get>::type type
+ };
+ }
+
+So the user can do the following
+
+ result_of::fork_all<AE, f, g, h>::type res = bith::fork_all(ae, f, g, h);
+ result_of::get_all<result_of::fork_all<AE, f, g, h>::type>::type values
+ = bith::get_all(handles);
+
+or using a typedef
+
+ typedef result_of::fork_all<AE, f, g, h>::type auto_type;
+ auto_type handles = bith::fork_all(ae, f, g, h);
+ result_of::get_all<auto_type>::type values= bith::get_all(handles);
+
+Note that the notation can be shortened by using the C++0x auto keyword.
+
+ auto res = bith::fork_all(ae, f, g, h);
+ auto values = bith::get_all(handles);
+
+Last but not least the library provides also some sugaring functions like
+wait_for_all that forks and wait for the result.
+
+ result_of::wait_for_all<AE, f, g, h>::type res = bith::wait_for_all(ae, f, g, h);
+ std::cout << get<1>(res) - get<0>(res) + get<2>(res) << std::endl;
+
+and wait_for_any which works with functions that return the same type or are convertible to the same type.
+
+ result_of::wait_for_any<AE, f, g, h>::type res = bith::wait_for_any(ae, f, g, h);
+ std::cout << "function " << res.first << " finshed first with result=" << res.second << std::endl;
+
+So the simple way to define a new AsynchronousExecutor is to define a class as
+
+ struct AsynchronousExecutor {
+ template <typename T>
+ struct handle {
+ typedef implementation-specific type;
+ };
+
+ template <typename F>
+ typename handle<typename result_of<F()>::type>::type
+ fork(F f);
+ };
+
+
+
+
+[endsect]
+
+[section Threader/Joiner]
+[/=============================================================================]
+
+Boost.Threads does offer a
+starting point, and with only a few considerations and changes it is relatively
+easy to evolve to the design described below from it.
+
+Threading in Boost.Threads is currently based on the idea that a thread is
+identified with an object that launches it. This notion is somewhat confused by
+the idea that on destruction the thread object is destroyed but the thread is not
+- in other words the thread is not identified the thread object... except when it
+is.
+
+Another appropriate separation is the distinction between initialization and
+execution. These are significantly different concepts but they are conflated in
+the existing thread-launching interface: the constructor is responsible both for
+preparing the thread and launching it, which means that it is not possible for
+one piece of code to set up a thread and another to initiate it separately at its
+own discretion, e.g. thread pools. Separating the two roles into constructor and
+executor function clears up both the technical and the conceptual issue. The
+executor function can be reasonably expressed as an overloaded function-call
+operator, or a start function.
+
+ void task();
+ ...
+ thread async_function;
+ ...
+ asynch_functiont(task);
+
+The separation also offers a simple and non-intrusive avenue for platform specific
+extension of how a thread is to execute: configuration details such as
+scheduling policy, stack size, security attributes, etc, can be added as
+parameters to t without intruding on the signatures of any other function in the
+threading interface:
+
+ size_t stack_size = ...;
+ security_attributes security(...);
+ thread async_function(stack_size, security);
+
+The default constructor could be the feature standardized, and the Boost
+implementation could add additional constructors as appropriate.
+
+Given that the same configuration might be used to launch other threads, and
+given the identity confusion of a thread being an object except when it's not, we
+can consider the interface not to be the interface of a thread but to be the
+interface of a thread launcher, i.e. an executor. A thread initiator can submit
+zero-argument functions and function objects to an executor for execution:
+
+ threader run;
+ ...
+ run(first_task);
+ run(second_task);
+
+Boost.InterThreads offers several asynchronous executors types and variables, but as
+a concept an asynchronous executor could be implemented in a variety of ways that still
+conform to the same basic launching interface, i.e. the function-call operator..
+
+Given that a threader can be used to launch multiple threads, there is the
+obvious question of how to join with each separately run thread. Instead of
+returning void, the threader returns an object whose primary purpose is to
+represent the ability to join with the completion of a separately executing thread
+of control.
+
+ joiner wait = run(first_task);
+
+The role played by the joiner in this fragment is that of an asynchronous
+completion token, a common pattern for synchronizing with and controlling
+asynchronous tasks. Via the joiner the initiator can poll or wait
+for the completion of the running thread, and control it in other ways, some of
+which may be platform specific extensions.
+
+joiner is Movable. Its principal action, the act of joining, can be expressed as a function
+call:
+joiner join = run(first_task);
+...
+join();
+
+If there are no joiners for a given thread, that thread is considered detached, a
+role currently played in Boost.Threads by the thread destructor:
+
+ run(second_task); // runs detached because return value ignored
+
+Boost.Threads does
+not return a value from a completed thread when joined. For many threaded
+tasks this makes sense, but where a thread is working towards a result then the
+idea that an asynchronously executed function can return a value for later
+collection should not be discarded. With a void-returning interface the
+programmer is forced to set up an arrangement for the threaded task to
+communicate a value to the party that wants the one-time result. This is tedious
+for such a simple case, and can be readily catered for by making the joiner a
+proper future variable that proxies the result. This leads to the threader
+interface looking like the following:
+
+ class threader
+ {
+ public:
+ threader();
+
+ template<typename nullary_function>
+ joiner<result_of<nullary_function()>::type> operator()(nullary_function);
+ ...
+ };
+
+For the common default configured threader, a wrapper function, fork, can be
+provided:
+
+ template<typename nullary_function>
+ joiner<result_of<nullary_function>::type> fork(nullary_function);
+
+And use it as follows:
+
+ void void_task();
+ int int_task();
+ ...
+ joiner<void> t1 = fork(void_task);
+ joiner<int> t2 = fork(int_task);
+ ...
+ int result = t1.get();
+ t2.join();
+
+The benefit of programming with futures is that for a certain class of code that
+would use end-of-thread synchronization to pick up results, programmers are
+not presented with unnecessarily low-level synchronization APIs. The function based
+model is applied consistently.
+
+When the application needs only the result it seems interesting to return only
+the future value associated to the unary function result..
+
+ unique_future<int> t3 = launch(int_task);
+
+
+[endsect]
+
+[section Decorators]
+[/=============================================================================]
`boost::call_once` provides a mechanism for ensuring that an initialization routine is run exactly once on a
programm without data races or deadlocks.
@@ -23,7 +513,7 @@
}
// ...
{
- boost::thread th(thread_main);
+ launch(thread_main);
//...
}
@@ -72,11 +562,19 @@
boost::thread th(boost::interthreads::make_decorator(thread_main));
//...
}
+
+We can use a basic_threader_decorator as asynchronous executor to fork thread_main.
+ // ...
+ {
+ boost::thread th=fork(basic_threader_decorator(), thread_main);
+ //...
+ }
[endsect]
-[section:thread_specific_shared_ptr_Motivation Sharing Thread Local Storage]
+[section Sharing Thread Local Storage]
+[/=============================================================================]
Thread local storage allows multi-threaded applications to have a separate instance of a given data item for
each thread. But do not provide any mechanism to access this data from other threads. Although this seems to
@@ -113,7 +611,8 @@
[endsect]
-[section:thread_tuple_motovation Thread Tuple]
+[section Thread Tuple]
+[/=============================================================================]
The __thread_group__ class allows to group dynamically threads. This means that the container must be dynamic.
@@ -128,16 +627,20 @@
The __thread_tuple__ class is responsible for launching and managing a static collection of threads
that are related in some fashion. No new threads can be added to the tuple once constructed. So we can write
- boost::interthreads:thread_join(thread1, tg.create_thread(thread2));
+ {
+ bith::thread_tuple<2> tt(thread1, thread2);
+ tt.join_all(thread1);
+ }
+
+As this
+ bith::conc_join_all(thread1, thread2);
In addition the user can join the first finishing thread.
- unsigned i = boost::interthreads:thread_join_first_then_interrupt(thread1, thread2);
-
+ unsigned i = bith::conc_join_any(thread1, thread2);
-Evidently, thread_tuple can not be used when we needs dynamic creation or deletion
-The __thread_group__ class allows to group dynamically threads.
+Evidently, thread_tuple can not be used when we needs dynamic creation or deletion. The __thread_group__ class allows to group dynamically threads.
{
boost::thread_group tg;
@@ -161,7 +664,7 @@
void f()
{
- boost::interthreads::thread_tuple<2> some_thread_tuple=make_thread_tuple(f1, g2);
+ bith::thread_tuple<2> some_thread_tuple=bith::make_thread_tuple(f1, g2);
some_thread_tuple.join();
}
Modified: sandbox/interthreads/libs/interthreads/doc/overview.qbk
==============================================================================
--- sandbox/interthreads/libs/interthreads/doc/overview.qbk (original)
+++ sandbox/interthreads/libs/interthreads/doc/overview.qbk 2009-01-04 13:01:47 EST (Sun, 04 Jan 2009)
@@ -15,6 +15,9 @@
__boost_interthreads__ extends __boost_thread__ adding some features:
+* threader/joiner: A Threader runs a unary function in its own thread. A Joiner is used to synchronise with and pick
+up the result from the unary function.
+
* thread decorator: thread_decorator allows to define setup/cleanup functions which will be called only once by thread:
setup before the thread function and cleanup at thread exit.
@@ -38,9 +41,13 @@
* thread_group_once: an extension of the boost::thread_group which allows to join the thread finishing
the first, using for that the set_once synchronizer.
-(thread_decorator and thread_specific_shared_ptr) are based on the original implementation of
-[@http://www.boost-consulting.com/vault/index.php?directory=Concurrent%20Programming [*threadalert]] written by Roland Schwarz.
-
+thread_decorator and thread_specific_shared_ptr are based on the original implementation of
+[@http://www.boost-consulting.com/vault/index.php?directory=Concurrent%20Programming [*threadalert]]
+written by Roland Schwarz.
+
+threader/joiner are based on the original idea of Kevlin Henney
+[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1883.pdf Preliminary Threading Library
+Proposal for TR2]
[/====================================]
[heading How to Use This Documentation]
@@ -68,7 +75,7 @@
Finally, you can mentally add the following to any code fragments in this document:
- // Include all of Proto
+ // Include all of InterThreads
#include <boost/interthreads/interthreads.hpp>
// Create a namespace aliases
Modified: sandbox/interthreads/libs/interthreads/doc/reference.qbk
==============================================================================
--- sandbox/interthreads/libs/interthreads/doc/reference.qbk (original)
+++ sandbox/interthreads/libs/interthreads/doc/reference.qbk 2009-01-04 13:01:47 EST (Sun, 04 Jan 2009)
@@ -9,6 +9,977 @@
[/==========================]
[/==========================================================================================]
+[section Header `<boost/interthreads/fork.hpp>`]
+[/==========================================================================================]
+
+ namespace boost {
+ namespace interthreads {
+ namespace result_of {
+ template <typename AE, typename F, typename A1, ..., typename An>
+ struct fork;
+ typedef typename AE::handle<typename result_of<F(A1, ..., An)> >::type type;
+ };
+ }
+
+ template< typename AE, typename F >
+ typename result_of::fork<AE,F>::type
+ fork( AE& ae, F fn );
+
+ template< typename AE, typename F, typename A1 >
+ typename result_of::fork<AE,F, mpl::vector<A1> >::type> >::type
+ fork( AE& ae, F fn, A1 a1 );
+
+ template< typename F >
+ typename result_of::fork<default_asynchronous_executor,F>::type
+ fork( F fn );
+
+ template< typename F, typename A1 >
+ typename result_of::forkT<default_asynchronous_executor,typename result_of<F(A1)>::type >::type
+ fork( F fn, A1 a1 );
+
+ }
+ }
+
+
+
+[section Metafunction `result_of::fork<AE,F> `]
+[/==========================================================================================]
+
+A metafunction returning the result type of applying fork to an asynchronous executor and a Nullary functor.
+
+ namespace result_of {
+ template <typename AE, typename F, typename A1, ..., typename An>
+ struct fork;
+ typedef typename AE::handle<typename result_of<F(A1, ..., An)> >::type type;
+ };
+ }
+
+[table fork Parameters
+ [
+ [[*Parameter]]
+ [[*Requirement]]
+ [[*Description]]
+ ]
+ [
+ [`AE`]
+ [A model of `AsynchrousExecutor`]
+ [Operation's argument ]
+ ]
+ [
+ [`F`]
+ [A model of n-ary function]
+ [Operation's argument ]
+ ]
+ [
+ [`Ak`]
+ [A model of n-ary function]
+ [n-ary function argument type for argument k]
+ ]
+]
+
+[variablelist
+[[Expression:] [result_of::fork<AE,F,A1,...,An>::type]]
+[[Return type:] [AE::handle<typename result_of<F(A1,...,An)> >::type]]
+]
+
+[endsect]
+
+[section Non member function `fork()`]
+[/==========================================================================================]
+
+ template< typename AE, typename F, typename A1 , ... typename An >
+ typename result_of::fork<AE,F, A1, An> >::type> >::type
+ fork( AE& ae, F fn, A1 a1 , ..., An an );
+
+[table fork Parameters
+ [
+ [[*Parameter]]
+ [[*Requirement]]
+ [[*Description]]
+ ]
+ [
+ [`AE`]
+ [A model of `AsynchrousExecutor`]
+ [Operation's argument ]
+ ]
+ [
+ [`F`]
+ [A model of n-ary function]
+ [Operation's argument ]
+ ]
+]
+
+[variablelist
+[[Requires:] [The expression fn(a1, ..., an) must be valid and
+have a type convertible to R, where R is typename result_of<Fn()>::type..]]
+[[Efect:] [Request the `AE` to creates a thread of execution for the function `fn`
+Request the asynchronous evaluation the expression `fn()` with respect to the calling thread to the
+asynchronous executor `ae` and
+places its result in an object h of type AE::handle<R>::type as if by using h.set_value( fn() ).
+If the expression fn() throws an exception e, places e into h as if by using
+h.set_exception( current_exception() ).]]
+]
+[[Returns:] [the AE handle h.]]
+
+[endsect]
+[endsect]
+
+[/==========================================================================================]
+[section Header `<boost/interthreads/fork_all.hpp>`]
+[/==========================================================================================]
+
+ namespace boost {
+ namespace interthreads {
+ namespace result_of {
+ template <typename AE, typename T>
+ struct fork_all;
+ template <typename AE, typename F1, ..., typename Fn>
+ struct fork_all <AE,fusion::tuple<F1, ..., Fn> >{
+ typedef fusion::tuple<
+ typename result_of::fork<AE,F1>::type,
+ ...
+ typename result_of::fork<AE,Fn>::type
+ > type;
+ };
+ }
+
+ template< typename AE, typename F1, ..., typename Fn>
+ typename result_of::fork_all<AE, mpl::tuple<F1, ..., Fn> >::type
+ fork_all( AE& ae, F1 f1, ..., Fn fn );
+
+ template< typename F1, ..., typename Fn>
+ typename result_of::fork_all<default_asynchronous_executor, F1, ..., Fn>::type
+ fork_all( F1 f1, ..., Fn fn );
+
+ }
+ }
+
+[section Metafunction `result_of::fork_all<AE,F1, ..., Fn> `]
+[/==========================================================================================]
+
+A metafunction returning the result type of applying fork_all to an asynchronous executor and n Nullary functors.
+
+ namespace result_of {
+ template <typename AE, typename T>
+ struct fork_all;
+ template <typename AE, typename F1, ..., typename Fn>
+ struct fork_all <AE,fusion::tuple<F1, ..., Fn> >{
+ typedef fusion::tuple<
+ typename result_of::fork<AE,F1>::type,
+ ...
+ typename result_of::fork<AE,Fn>::type
+ > type;
+ };
+ }
+
+[table fork_all Parameters
+ [
+ [[*Parameter]]
+ [[*Requirement]]
+ [[*Description]]
+ ]
+ [
+ [`AE`]
+ [A model of `AsynchrousExecutor`]
+ [Operation's argument ]
+ ]
+ [
+ [`Fk`]
+ [A model of nullary function]
+ [Operation's argument ]
+ ]
+]
+
+[variablelist
+[[Expression:] [`result_of::fork_all<AE,F1,...,Fn>::type`]]
+[[Return type:] [a fusion tuple of the result of forking each `Fk` by the `AE`]]
+]
+
+[endsect]
+
+[section Non member function `fork_all()`]
+[/==========================================================================================]
+
+ template< typename AE, typename F1, ..., typename Fn>
+ typename result_of::fork_all<AE, mpl::tuple<F1, ..., Fn> >::type
+ fork_all( AE& ae, F1 f1, ..., Fn fn );
+
+ template< typename F1, ..., typename Fn>
+ typename result_of::fork_all<default_asynchronous_executor, F1, ..., Fn>::type
+ fork_all( F1 f1, ..., Fn fn );
+
+[table fork Parameters
+ [
+ [[*Parameter]]
+ [[*Requirement]]
+ [[*Description]]
+ ]
+ [
+ [`AE`]
+ [A model of `AsynchrousExecutor`]
+ [Operation's argument ]
+ ]
+ [
+ [`Fk`]
+ [A model of nullary function]
+ [Operation's argument ]
+ ]
+]
+
+[variablelist
+[[Returns:] [a fusion tuple of the result of forking each `fk` by the `ae`]]
+[[Efect:] [Request the `AE` to creates a n thread of execution one for the function `fk`.]]
+]
+
+[endsect]
+
+
+[endsect]
+
+
+[/==========================================================================================]
+[section Header `<boost/interthreads/algorithm.hpp>`]
+[/==========================================================================================]
+
+ #include <boost/interthreads/algorithm/join_all.hpp>
+ #include <boost/interthreads/algorithm/join_all_until.hpp>
+ #include <boost/interthreads/algorithm/wait_all.hpp>
+ #include <boost/interthreads/algorithm/wait_all_until.hpp>
+ #include <boost/interthreads/algorithm/get_all.hpp>
+ #include <boost/interthreads/algorithm/get_all_until.hpp>
+ #include <boost/interthreads/algorithm/detach_all.hpp>
+ #include <boost/interthreads/algorithm/interrupt_all.hpp>
+ #include <boost/interthreads/algorithm/interruption_requested_on_all.hpp>
+
+[endsect]
+
+[/==========================================================================================]
+[section Header `<boost/interthreads/algorithm/get_all.hpp>`]
+[/==========================================================================================]
+
+ namespace boost {
+ namespace interthreads {
+ namespace fct {
+ struct get {
+ template<typename T>
+ typename T::result_type operator()(T& t);
+ };
+ }
+ namespace result_of {
+ template <typename Sequence>
+ struct get_all {
+ typedef typename result_of::transform<Sequence, fct::get>::type type;
+ };
+ }
+ namespace algo {
+ template <typename Sequence>
+ typename result_of::get_all<Sequence>::type
+ get_all(Sequence& mt);
+ }
+ }
+ }
+
+[section Functor `fct::get<>`]
+[/==========================================================================================]
+
+ namespace fct {
+ struct get {
+ template<typename AE>
+ typename AE::result_type operator()(AE& ae);
+ };
+ }
+
+
+[variablelist
+[[Returns:] [The result of the AE::get().]]
+]
+
+[endsect]
+
+[section Metafunction `result_of::get_all<AE,F1, ..., Fn> `]
+[/==========================================================================================]
+
+A metafunction returning the result type of applying get_all to a Sequence of asynchronous executor.
+
+ namespace result_of {
+ template <typename Sequence>
+ struct get_all {
+ typedef typename result_of::transform<Sequence, fct::get>::type type;
+ };
+ }
+
+[table fork_all Parameters
+ [
+ [[*Parameter]]
+ [[*Requirement]]
+ [[*Description]]
+ ]
+ [
+ [`Sequence`]
+ [A sequence of of `AsynchrousExecutor`s]
+ [Operation's argument ]
+ ]
+]
+
+[variablelist
+[[Expression:] [`result_of::get_all<S>::type`]]
+[[Return type:] [a fusion tuple of the result of applying get to each one of the asynchronous executors in the sequence]]
+]
+
+[endsect]
+
+[section Non member function `get_all`]
+[/==========================================================================================]
+
+ namespace algo {
+ template <typename Sequence>
+ typename result_of::get_all<Sequence>::type
+ get_all(Sequence& mt);
+ }
+
+
+[variablelist
+[[Returns:] [a fusion tuple of the result of applying get to each one of the asynchronous executors handles in the sequence.]]
+[[Effect:] [Blocks until all the AE handles are ready.]]
+
+]
+
+[endsect]
+
+[endsect]
+
+[/==========================================================================================]
+[section Header `<boost/interthreads/wait_for_all.hpp>`]
+[/==========================================================================================]
+
+ namespace boost {
+ namespace interthreads {
+ namespace result_of {
+ template <typename AE, typename F1, ..., typename Fn>
+ struct wait_for_all {
+ typedef fusion::tuple<
+ typename result_of<F1()>::type,
+ ...
+ typename result_of<Fn()>::type,
+ > type;
+ };
+ }
+
+ template< typename AE, typename F1, ..., typename Fn>
+ typename result_of::wait_for_all<AE, F1, ..., Fn>::type
+ wait_for_all( AE& ae, F1 f1, ..., Fn fn );
+ }
+ }
+
+[section Metafunction `result_of::wait_for_all<AE,F1, ..., Fn> `]
+[/==========================================================================================]
+
+A metafunction returning the result type of applying get_all to a Sequence of asynchronous executor handles.
+
+ namespace result_of {
+ template <typename AE, typename F1, ..., typename Fn>
+ struct wait_for_all {
+ typedef fusion::tuple<
+ typename result_of<F1()>::type,
+ ...
+ typename result_of<Fn()>::type,
+ > type;
+ };
+ }
+
+[table wait_for_all Parameters
+ [
+ [[*Parameter]]
+ [[*Requirement]]
+ [[*Description]]
+ ]
+ [
+ [`AE`]
+ [A model of `AsynchrousExecutor`]
+ [Operation's argument ]
+ ]
+ [
+ [`Fk`]
+ [A model of nullary function]
+ [Operation's argument ]
+ ]
+]
+
+[variablelist
+[[Expression:] [`result_of::wait_for_all<AE, F1, ..., Fn>::type`]]
+[[Return type:] [a fusion tuple of the result of applying get to each one of the asynchronous executors handles resulting of forking each function `Fk` by `AE`]]
+]
+
+[endsect]
+
+[section Non member function `wait_for_all`]
+[/==========================================================================================]
+
+ template< typename AE, typename F1, ..., typename Fn>
+ typename result_of::wait_for_all<AE, F1, ..., Fn>::type
+ wait_for_all( AE& ae, F1 f1, ..., Fn fn );
+
+
+[variablelist
+[[Returns:] [a fusion tuple of the result of applying get to each one of the asynchronous executors handles resulting of forking each function `fk` by `ae`.]]
+[[Effect:] [Request the `AE` to creates a n thread of execution one for the function `fk` and
+blocks until all the AE handles are ready.]]
+
+]
+
+[endsect]
+[endsect]
+
+[/==========================================================================================]
+[section Header `<boost/interthreads/wait_for_any.hpp>`]
+[/==========================================================================================]
+
+ namespace boost {
+ namespace interthreads {
+ namespace result_of {
+ template <typename AE, typename F1, ..., typename Fn>
+ struct wait_for_any {
+ // requires typename result_of<F1()>::type == typename result_of<Fk()>::type
+ typedef std::pair<unsigned,typename result_of<F1()>::type> type;
+ };
+ }
+
+ template< typename AE, typename F1, ..., typename Fn>
+ typename result_of::wait_for_any<AE, F1, ..., Fn>::type
+ wait_for_any( AE& ae, F1 f1, ..., Fn fn );
+ }
+ }
+
+[section Metafunction `result_of::wait_for_all<AE,F1, ..., Fn> `]
+[/==========================================================================================]
+
+A metafunction returning the a pair: the index of the first function executed by the AE and the result type
+of applying get on an asynchronous executor handles.
+
+ namespace result_of {
+ template <typename AE, typename F1, ..., typename Fn>
+ struct wait_for_any {
+ // requires typename result_of<F1()>::type == typename result_of<Fk()>::type
+ typedef std::pair<unsigned,typename result_of<F1()>::type> type;
+ };
+ }
+
+[table wait_for_all Parameters
+ [
+ [[*Parameter]]
+ [[*Requirement]]
+ [[*Description]]
+ ]
+ [
+ [`AE`]
+ [A model of `AsynchrousExecutor`]
+ [Operation's argument ]
+ ]
+ [
+ [`Fk`]
+ [A model of nullary function]
+ [Operation's argument ]
+ ]
+]
+
+[variablelist
+[[Expression:] [`result_of::wait_for_any<AE, F1, ..., Fn>::type`]]
+[[Return type:] [a pair: the index of the first function executed by the AE and the result type
+of applying get on an asynchronous executor handles created by `ae` to fork each `fk`]]
+]
+
+[endsect]
+
+[section Non member function `wait_for_any`]
+[/==========================================================================================]
+
+ template< typename AE, typename F1, ..., typename Fn>
+ typename result_of::wait_for_any<AE, F1, ..., Fn>::type
+ wait_for_any( AE& ae, F1 f1, ..., Fn fn );
+
+
+[variablelist
+[[Returns:] [a fusion tuple of the result of applying get to each one of the asynchronous executors handles resulting of forking each function `fk` by `ae`.]]
+[[Effect:] [Request the `AE` to creates a n thread of execution one for the function `fk` and
+blocks until all the AE handles are ready.]]
+
+]
+
+[endsect]
+
+[endsect]
+
+
+[/==========================================================================================]
+[section Header `<boost/interthreads/launcher.hpp>`]
+[/==========================================================================================]
+
+ #include <boost/interthreads/fork.hpp>
+ namespace boost {
+ namespace interthreads {
+ class launcher;
+ }
+ }
+
+[section Class `launcher `]
+[/==========================================================================================]
+
+Thread launcher using a common configuration managed with the thread attributes and
+returning on the fork operation a unique_future to the resulting type of the call to the threaded function.
+
+ class launcher {
+ public:
+ thread::native_handle_attr_type& attr();
+
+ template <typename T>
+ struct handle {
+ typedef unique_future<T> > type;
+ };
+
+ template <typename F>
+ unique_future<typename result_of<F()>::type>
+ fork(F f);
+ };
+
+[section Member function `lancher::attributes`]
+[/==========================================================================================]
+
+Reference to the thread attributes accesor.
+
+ thread::native_handle_attr_type& attributes();
+
+[variablelist
+[[Returns:] [A reference to the thread attributes.]]
+[[Complexity:] [constant.]]
+]
+
+
+[endsect]
+[section Metafunction `launcher::handle<>`]
+[/==========================================================================================]
+
+Metafunction that returns the result type of the fork function applied to a launcher and the value type.
+
+ template <typename T>
+ struct handle {
+ typedef unique_future<T> > type;
+ };
+
+[variablelist
+[[Expression:] [L::handle<T>::type]]
+[[Return type:] [A unique_future<T>.]]
+[[Complexity:] [constant.]]
+
+]
+
+[endsect]
+
+[section Member function `lancher::fork`]
+[/==========================================================================================]
+
+ template <typename F>
+ unique_future<typename result_of<F()>::type>
+ fork(F f);
+
+[variablelist
+[[Returns:] [A unique_future to the result of calling a function F.]]
+[[Effects:] [create a thread executing the function f.
+ The result of the function will be stored on the resulting future.]]
+
+]
+
+
+[endsect]
+
+
+[endsect]
+
+[endsect]
+
+[/==========================================================================================]
+[section Header `<boost/interthreads/threader.hpp>`]
+[/==========================================================================================]
+
+ #include <boost/interthreads/fork.hpp>
+ namespace boost {
+ namespace interthreads {
+ template <typename ResultType>
+ class joiner;
+
+ template <typename ResultType>
+ void swap(joiner<ResultType>& lhs,joiner<ResultType>& rhs);
+
+ class threader;
+ }
+ }
+
+[/==================================================]
+[section Template Class `joiner`]
+[/==========================================================================================]
+
+
+template <typename ResultType>
+class joiner {
+ typedef joiner this_type;
+public:
+ joiner(const joiner& rhs) = delete;
+ joiner& operator=(const joiner& rhs) = delete;
+
+ typedef ResultType result_type;
+
+ template <typename Nullary>
+ joiner(thread::native_handle_attr_type& attr, Nullary f);
+ template <typename Nullary>
+ joiner(Nullary f);
+
+ joiner(boost::detail::thread_move_t<joiner> x);
+ joiner& operator=(boost::detail::thread_move_t<joiner> x);
+ operator boost::detail::thread_move_t<joiner>();
+ boost::detail::thread_move_t<joiner> move();
+
+ void swap(this_type& x);
+
+ bool joinable() const;
+ void join();
+ bool join_until(const system_time& abs_time);
+ template<typename TimeDuration>
+ inline bool join_for(TimeDuration const& rel_time);
+
+ result_type get();
+ result_type operator()();
+
+ bool is_ready() const;
+ bool has_exception() const;
+ bool has_value() const;
+
+ void wait() const;
+ bool wait_until(const system_time& abs_time) const;
+ template<typename TimeDuration>
+ inline bool wait_for(TimeDuration const& rel_time) const;
+
+ thread::id get_id() const;
+ void detach();
+ void interrupt();
+ bool interruption_requested() const;
+
+ typedef platform-specific-type native_handle_type;
+ native_handle_type native_handle();
+
+};
+
+
+[section:destructor Joiner Destructor]
+[/==========================================================================================]
+
+ ~joiner();
+
+[variablelist
+[[Effects:] [If `*this` has an associated thread of execution, calls __detach__. Destroys `*this`.]]
+[[Throws:] [Nothing.]]
+]
+
+[endsect]
+
+[section:swap Member function `swap()`]
+
+ void swap(joiner& other);
+
+[variablelist
+[[Effects:] [Exchanges the threads of execution associated with `*this` and `other`, so `*this` is associated with the thread of
+execution associated with `other` prior to the call, and vice-versa.]]
+[[Postconditions:] [`this->get_id()` returns the same value as `other.get_id()` prior to the call. `other.get_id()` returns the same
+value as `this->get_id()` prior to the call.]]
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+
+[section Member Function `get()|operator()()`]
+[/==========================================================================================]
+
+ result_type get();
+ result_type operator()();
+
+[variablelist
+[[Effects:] [Retrieves the value returned by the Nullary function.]]
+[[Sychronization:][The completion of the call to the operator()() the Nullary function happens before get() returns.]]
+[[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.]]
+[[Throws:] [the stored exception, if an exception was stored and not retrieved before.]]
+[[Postconditions:] [It is unspecified what happens when get() is called a second time on the same joiner.]]
+[[Thread safety:][unsafe]]
+]
+[endsect]
+
+
+[section Member Function `is_ready()`]
+[/==========================================================================================]
+
+ bool is_ready() const;
+
+[variablelist
+[[Returns:] [true only if the associated state holds a value or an exception ready for retrieval.]]
+[[Remark:] [the return value is unspecified after a call to get().]]
+]
+[endsect]
+
+[section Member Function `has_exception()`]
+[/==========================================================================================]
+
+ bool has_exception() const;
+
+[variablelist
+[[Returns:] [true only if is_ready() == true and the associated state contains an exception.]]
+]
+[endsect]
+
+[section Member Function `has_value()`]
+[/==========================================================================================]
+
+ bool has_value() const;
+
+[variablelist
+[[Returns:] [true only if is_ready() == true and the associated state contains a value.]]
+]
+[endsect]
+
+[section Member Function `wait()`]
+[/==========================================================================================]
+
+ void wait();
+
+[variablelist
+[[Effects:] [Blocks until the Nullariry function ends.]]
+[[Sychronization:][The completion of the call to the operator()() the Nullary function happens before wait() returns.]]
+[[Throws:] [the stored exception, if an exception was stored and not retrieved before.]]
+[[Postconditions:] [is_ready() == true.]]
+[[Thread safety:][unsafe]]
+]
+[endsect]
+
+[section Member Function `wait_until()|wait_for()`]
+[/==========================================================================================]
+
+ bool wait_until(const system_time& abs_time);
+ template<typename TimeDuration>
+ bool wait_for(TimeDuration const& rel_time);
+
+
+[variablelist
+[[Effects:] [Blocks until the Nullariry function ends.]]
+[[Sychronization:][The completion of the call to the operator()() the Nullary function happens before wait() returns.]]
+[[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.]]
+[[Throws:] [the stored exception, if an exception was stored and not retrieved before.]]
+[[Postconditions:] [is_ready() == true.]]
+[[Thread safety:][unsafe]]
+]
+[endsect]
+
+
+
+[section:joinable Member function `joinable()`]
+[/==========================================================================================]
+
+ bool joinable() const;
+
+[variablelist
+[[Returns:] [`true` if `*this` refers to a thread of execution, `false` otherwise.]]
+[[Throws:] [Nothing]]
+]
+
+[endsect]
+
+[section:join Member function `join()`]
+[/==========================================================================================]
+
+ void join();
+
+[variablelist
+[[Preconditions:] [`this->get_id()!=boost::this_thread::get_id()`]]
+[[Effects:] [If `*this` refers to a thread of execution, waits for that thread of execution to complete.]]
+[[Postconditions:] [If `*this` refers to a thread of execution on entry, that thread of execution has completed. `*this` no longer refers to any thread of execution.]]
+[[Throws:] [__thread_interrupted__ if the current thread of execution is interrupted.]]
+[[Notes:] [`join()` is one of the predefined __interruption_points__.]]
+]
+
+[endsect]
+
+[section Member function `join_until()|join_for()`]
+[/==========================================================================================]
+
+ bool join_until(const system_time& wait_until);
+
+ template<typename TimeDuration>
+ bool join_for(TimeDuration const& rel_time);
+
+[variablelist
+[[Preconditions:] [`this->get_id()!=boost::this_thread::get_id()`]]
+[[Effects:] [If `*this` refers to a thread of execution, waits for that thread of execution to complete, the time `wait_until` has
+been reach or the specified duration `rel_time` has elapsed. If `*this` doesn't refer to a thread of execution, returns immediately.]]
+[[Returns:] [`true` if `*this` refers to a thread of execution on entry, and that thread of execution has completed before the call
+times out, `false` otherwise.]]
+[[Postconditions:] [If `*this` refers to a thread of execution on entry, and `timed_join` returns `true`, that thread of execution
+has completed, and `*this` no longer refers to any thread of execution. If this call to `timed_join` returns `false`, `*this` is
+unchanged.]]
+[[Throws:] [__thread_interrupted__ if the current thread of execution is interrupted.]]
+[[Notes:] [`timed_join()` is one of the predefined __interruption_points__.]]
+]
+
+[endsect]
+
+[section:detach Member function `detach()`]
+[/==========================================================================================]
+
+ void detach();
+
+[variablelist
+[[Effects:] [If `*this` refers to a thread of execution, that thread of execution becomes detached, and no longer has an associated __thread__ object.]]
+[[Postconditions:] [`*this` no longer refers to any thread of execution.]]
+[[Throws:] [Nothing]]
+]
+
+[endsect]
+
+
+[section:get_id Member function `get_id()`]
+[/==========================================================================================]
+
+ thread::id get_id() const;
+
+[variablelist
+[[Returns:] [If `*this` refers to a thread of execution, an instance of __thread_id__ that represents that thread. Otherwise returns
+a default-constructed __thread_id__.]]
+[[Throws:] [Nothing]]
+]
+
+[endsect]
+
+[section:interrupt Member function `interrupt()`]
+[/==========================================================================================]
+
+ void interrupt();
+
+[variablelist
+[[Effects:] [If `*this` refers to a thread of execution, request that the thread will be interrupted the next time it enters one of
+the predefined __interruption_points__ with interruption enabled, or if it is currently __blocked__ in a call to one of the
+predefined __interruption_points__ with interruption enabled .]]
+[[Throws:] [Nothing]]
+]
+
+
+[endsect]
+
+
+[section:nativehandle Member function `native_handle()`]
+[/==========================================================================================]
+
+ typedef platform-specific-type native_handle_type;
+ native_handle_type native_handle();
+
+[variablelist
+[[Effects:] [Returns an instance of `native_handle_type` that can be used with platform-specific APIs to manipulate the underlying
+implementation. If no such instance exists, `native_handle()` and `native_handle_type` are not present.]]
+[[Throws:] [Nothing.]]
+]
+
+[endsect]
+
+
+
+[endsect]
+[section:non_member_swap Non-member function `swap()`]
+
+ void swap(joiner& lhs,joiner& rhs);
+
+[variablelist
+
+[[Effects:] [[link thread.thread_management.thread.swap `lhs.swap(rhs)`].]]
+
+]
+
+[endsect]
+
+[/==================================================]
+[section Template Class `threader`]
+[/==========================================================================================]
+
+ class threader {
+ public:
+ thread::native_handle_attr_type& attributes();
+
+ template <typename T>
+ struct handle {
+ typedef joiner<T> type;
+ };
+
+ template <typename F>
+ joiner<typename result_of<F()>::type>
+ fork(F f);
+
+ };
+
+[section Member function `threader::attributes()`]
+[/==========================================================================================]
+
+Reference to the thread attributes accesor.
+
+ thread::native_handle_attr_type& attributes();
+
+[variablelist
+[[Returns:] [A reference to the thread attributes.]]
+[[Complexity:] [constant.]]
+]
+
+
+[endsect]
+[section Metafunction `threader::handle<>`]
+[/==========================================================================================]
+
+Metafunction that returns the result type of the fork function applied to a threader and the value type.
+
+ template <typename T>
+ struct handle {
+ typedef joiner<T> type;
+ };
+
+
+[variablelist
+[[Expression:] [L::handle<T>::type]]
+[[Return type:] [A joiner<T>.]]
+[[Complexity:] [constant.]]
+
+]
+
+[endsect]
+
+[section Member function `threader::fork`]
+[/==========================================================================================]
+
+ template <typename F>
+ joiner<typename result_of<F()>::type>
+ fork(F f);
+
+[variablelist
+[[Returns:] [A joiner to the result of calling a function F.]]
+[[Effects:] [create a thread executing the function f.
+ The result of the function will be stored on the resulting joiner.]]
+
+]
+
+
+[endsect]
+
+[endsect]
+
+[endsect]
+
+
+[/==========================================================================================]
[section:decorator_thread_decoration_file Header `<boost/interthreads/thread_decorator.hpp>`]
[/==========================================================================================]
@@ -28,13 +999,13 @@
class thread_decoration {
public:
- template<typename Callable1>
- thread_decoration(Callable1 setup);
+ template<typename Callable1>
+ thread_decoration(Callable1 setup);
- template<typename Callable1,typename Callable2>
- thread_decoration(Callable1 setup, Callable2 cleanup);
+ template<typename Callable1,typename Callable2>
+ thread_decoration(Callable1 setup, Callable2 cleanup);
- ~thread_decoration() {
+ ~thread_decoration() {
};
[section:thread_decoration_class_constructor_setup Constructor with setup]
@@ -341,7 +1312,7 @@
[endsect]
-[section:thread_specific_shared_ptr_reference_Header Header `<boost/thread/thread_specific_shared_ptr.hpp>`]
+[section:thread_specific_shared_ptr_reference_Header Header `<boost/interthreads/thread_specific_shared_ptr.hpp>`]
[/==========================================================================================]
namespace boost {
@@ -830,14 +1801,10 @@
void swap(thread_tuple<n>& x);
bool joinable() const;
- void join();
void join_all();
- bool timed_join(const system_time& wait_until);
- template<typename TimeDuration>
- bool timed_join(TimeDuration const& rel_time);
- bool timed_join_all(const system_time& wait_until);
+ bool join_all_until(const system_time& wait_until);
template<typename TimeDuration>
- bool timed_join_all(TimeDuration const& rel_time);
+ bool join_all_for(TimeDuration const& rel_time);
void detach();
void detach_all();
@@ -919,7 +1886,7 @@
[endsect]
-[section:thread_tuple_join Member function `join()|join_all()`]
+[section:thread_tuple_join Member function `join_all()`]
[/==========================================================================================]
void join();
@@ -939,20 +1906,36 @@
[endsect]
-[section:thread_tuple_timed_join Member function `timed_join()|timed_join_all()`]
+[section Member function `join_all_until()`]
[/==========================================================================================]
- bool timed_join(const system_time& wait_until);
- template<typename TimeDuration>
- bool timed_join(TimeDuration const& rel_time);
+ bool join_all_until(const system_time& wait_until);
+
+[variablelist
+
+[[Effects:] [Call `timed_join()` on each __thread__ object in the tuple.]]
+
+[[Postcondition:] [Every thread in the tuple has terminated.]]
+
+[[Returns:] [true if joined.]]
+
+[[Throws:] [Nothing]]
+
+[[Note:] [Since `boost::thread::timed_join` is one of the predefined interruption points, `thread_tuple<>::join_all_until()` is also an interruption point.]]
+
+]
+
+[endsect]
+
+[section Member function `join_all_for()`]
+[/==========================================================================================]
- bool timed_join_all(const system_time& wait_until);
template<typename TimeDuration>
- bool timed_join_all(TimeDuration const& rel_time);
+ bool join_for(TimeDuration const& rel_time);
[variablelist
-[[Effects:] [Call `timed_join()` on each __thread__ object in the tuple.]]
+[[Effects:] [As `join_all_until(now()+rel_time)`.]]
[[Postcondition:] [Every thread in the tuple has terminated.]]
@@ -960,43 +1943,43 @@
[[Throws:] [Nothing]]
-[[Note:] [Since `boost::thread::timed_join` is one of the predefined interruption points, `thread_tuple<>::timed_join_all()` is also an interruption point.]]
+[[Note:] [Since `boost::thread::timed_join` is one of the predefined interruption points, `thread_tuple<>::join_all_for()` is also an interruption point.]]
]
[endsect]
-[section:join_first_then_interrupt Member function `join_first_then_interrupt()`]
+[section:join_first_then_interrupt Member function `join_any()`]
[/==========================================================================================]
- std::size_t join_first_then_interrupt();
+ std::size_t conc_join_any();
[variablelist
-[[Effects:] [Call `join_first()` and the `interrup_all()`.]]
+[[Effects:] [Call `join_any()` on a temporary thread_tuple and the `interrup_all()`.]]
[[Postcondition:] [Every thread in the tuple has terminated.]]
[[Throws:] [Nothing]]
-[[Note:] [Since `boost::thread::join` is one of the predefined interruption points, `thread_tuple<>::join_all()` is also an interruption point.]]
+[[Note:] [Since `join_any()` is one of the predefined interruption points, `conc_join_any()` is also an interruption point.]]
]
[endsect]
-[section:timed_join_first_then_interrupt Member function `timed_join_first_then_interrupt()`]
+[section Member function `join_any_until()`]
[/==========================================================================================]
- std::pair<bool,std::size_t> timed_join_first_then_interrupt(
+ std::pair<bool,std::size_t> conc_join_any_until(
const system_time& wait_until);
template<typename TimeDuration>
- std::pair<bool,std::size_t> timed_join_first_then_interrupt(
+ std::pair<bool,std::size_t> join_any_for(
TimeDuration const& rel_time);
[variablelist
-[[Effects:] [Call `timed_join_first()` and the `interrup_all()`.]]
+[[Effects:] [Call `join_any_until()` on a temporary thread_tuple and the `interrup_all()`.]]
[[Postcondition:] [Every thread in the tuple has terminated.]]
@@ -1004,16 +1987,15 @@
[[Throws:] [Nothing]]
-[[Note:] [Since `boost::thread::timed_join` is one of the predefined interruption points, `thread_tuple<>::timed_join_all()` is also an interruption point.]]
+[[Note:] [Since `join_any_until()` is one of the predefined interruption points, `conc_join_any_until()` is also an interruption point.]]
]
[endsect]
-[section:detach_all Member function `detach|detach_all()`]
+[section:detach_all Member function `detach_all()`]
[/==========================================================================================]
- void detach();
void detach_all();
[variablelist
@@ -1024,10 +2006,9 @@
[endsect]
-[section:thread_tuple_interrupt_all Member function `interrupt()|interrupt_all()`]
+[section:thread_tuple_interrupt_all Member function `interrupt_all()`]
[/==========================================================================================]
- void interrupt();
void interrupt_all();
[variablelist
@@ -1084,7 +2065,7 @@
}
-[section:set_onceclass Template Class `set_once_once<>`]
+[section:set_onceclass Template Class `set_once<>`]
[/==========================================================================================]
`set_once_once<>` is a synchonizer that allows to set a variable only once, notifying
@@ -1098,11 +2079,16 @@
set_once();
void wait();
- value_type get();
+ bool wait_until(const system_time& abs_time);
+ template<typename TimeDuration>
+ bool wait_for(const TimeDuration& rel_time);
- std::pair<bool,value_type> timed_get(const system_time& wait_until);
+ value_type get();
+ std::pair<bool,value_type> get_until(const system_time& abs_time);
+ template<typename TimeDuration>
+ std::pair<bool,value_type> get_for(const TimeDuration& rel_time);
- bool set(value_type id);
+ bool set_if_unassigned(value_type id);
template<typename F>
static void decorator(this_type& once, T value, F fct);
@@ -1154,27 +2140,21 @@
void swap(thread_tuple_once<n>& x);
- bool joinable() const;
- void join();
+ bool joinables() const;
void join_all();
- bool timed_join(const system_time& wait_until);
+ bool join_all_until(const system_time& wait_until);
template<typename TimeDuration>
- bool timed_join(TimeDuration const& rel_time);
- bool timed_join_all(const system_time& wait_until);
- template<typename TimeDuration>
- bool timed_join_all(TimeDuration const& rel_time);
+ bool join_all_for(TimeDuration const& rel_time);
- std::size_t join_first_then_interrupt();
- std::pair<bool,std::size_t> timed_join_first_then_interrupt(
+ std::size_t join_any();
+ std::pair<bool,std::size_t> join_any_until(
const system_time& wait_until);
template<typename TimeDuration>
- std::pair<bool,std::size_t> timed_join_first_then_interrupt(
+ std::pair<bool,std::size_t> join_any_for(
TimeDuration const& rel_time);
- void detach();
void detach_all();
- void interrupt();
void interrupt_all();
bool interruption_requested() const;
@@ -1236,10 +2216,10 @@
[endsect]
-[section:thread_tuple_once_joinable Member function `joinable()`]
+[section:thread_tuple_once_joinable Member function `joinables()`]
[/==========================================================================================]
- bool joinable() const;
+ bool joinables() const;
[variablelist
@@ -1251,10 +2231,9 @@
[endsect]
-[section:thread_tuple_once_join Member function `join()|join_all()`]
+[section:thread_tuple_once_join Member function `join_all()`]
[/==========================================================================================]
- void join();
void join_all();
[variablelist
@@ -1271,16 +2250,12 @@
[endsect]
-[section:thread_tuple_once_timed_join Member function `timed_join()|timed_join_all()`]
+[section Member function `join_all_until()`]
[/==========================================================================================]
- bool timed_join(const system_time& wait_until);
- template<typename TimeDuration>
- bool timed_join(TimeDuration const& rel_time);
-
- bool timed_join_all(const system_time& wait_until);
+ bool join_all_until(const system_time& wait_until);
template<typename TimeDuration>
- bool timed_join_all(TimeDuration const& rel_time);
+ bool join_all_for(TimeDuration const& rel_time);
[variablelist
@@ -1298,10 +2273,10 @@
[endsect]
-[section:join_first_then_interrupt Member function `join_first_then_interrupt()`]
+[section Member function `join_any()`]
[/==========================================================================================]
- std::size_t join_first_then_interrupt();
+ std::size_t join_any();
[variablelist
@@ -1342,10 +2317,9 @@
[endsect]
-[section:detach_all Member function `detach|detach_all()`]
+[section:detach_all Member function `detach_all()`]
[/==========================================================================================]
- void detach();
void detach_all();
[variablelist
@@ -1356,10 +2330,9 @@
[endsect]
-[section:thread_tuple_once_interrupt_all Member function `interrupt()|interrupt_all()`]
+[section:thread_tuple_once_interrupt_all Member function `interrupt_all()`]
[/==========================================================================================]
- void interrupt();
void interrupt_all();
[variablelist
@@ -1413,30 +2386,30 @@
namespace interthreads {
template<typename F0, ..., typename Fn-1>
- void thread_and_join_all(F0 f0, ..., Fn fn-1);
+ void conc_join_all(F0 f0, ..., Fn fn-1);
template<typename F0, ..., typename Fn-1>
- bool thread_and_timed_join_all(const system_time& wait_until, F0 f0, ..., Fn fn-1);
+ bool conc_join_all_until(const system_time& wait_until, F0 f0, ..., Fn fn-1);
template<typename TimeDuration, typename F0, ..., typename Fn-1>
- bool thread_and_timed_join_all(TimeDuration wait_for, F0 f0, ..., Fn fn-1);
+ bool conc_join_all_for(TimeDuration wait_for, F0 f0, ..., Fn fn-1);
template<typename F0, ..., typename Fn-1>
- std::size_t thread_and_join_first_then_interrupt(F0 f0, ..., Fn fn-1);
+ std::size_t conc_join_any(F0 f0, ..., Fn fn-1);
template<typename F0, ..., typename Fn-1>
- std::pair<bool,std::size_t> thread_and_timed_join_first_then_interrupt(
+ std::pair<bool,std::size_t> conc_join_any_until(
const system_time& wait_until, F0 f0, ..., Fn fn-1);
template<typename TimeDuration, typename F0, ..., typename Fn-1>
- std::pair<bool,std::size_t> thread_and_timed_join_first_then_interrupt(
+ std::pair<bool,std::size_t> conc_join_all_for(
TimeDuration wait_for, F0 f0, ..., Fn fn-1);
}
}
-[section:thread_tuple_join_all Non Member Function `thread_join_all()`]
+[section:conc_join_all Non Member Function `conc_join_all()`]
[/==========================================================================================]
template<typename F0, ..., typename Fn-1>
- void thread_join_all(F0 f0, ..., Fn fn-1);
+ void conc_join_all(F0 f0, ..., Fn fn-1);
[variablelist
@@ -1446,15 +2419,26 @@
[endsect]
-[section:thread_tuple_timed_join_all Non Member Function `thread_timed_join_all()`]
+[section:conc_join_all_until Non Member Function `conc_join_all_until()`]
[/==========================================================================================]
template<typename F0, ..., typename Fn-1>
- bool thread_timed_join_all(
- const system_time& wait_until, F0 f0, ..., Fn fn-1);
+ bool conc_join_all_until(const system_time& wait_until, F0 f0, ..., Fn fn-1);
+
+[variablelist
+
+[[Effects:] [launch each function on a thread of execution and join all until a given time or duration if not interrup all.]]
+[[Returns:] [true if joined.]]
+
+]
+
+[endsect]
+
+[section:conc_join_all_for Non Member Function `conc_join_all_for()`]
+[/==========================================================================================]
+
template<typename TimeDuration, typename F0, ..., typename Fn-1>
- bool thread_timed_join_all(
- TimeDuration wait_for, F0 f0, ..., Fn fn-1);
+ bool conc_join_all_for(TimeDuration wait_for, F0 f0, ..., Fn fn-1);
[variablelist
@@ -1465,12 +2449,20 @@
[endsect]
+ template<typename F0, ..., typename Fn-1>
+ std::size_t conc_join_any(F0 f0, ..., Fn fn-1);
+ template<typename F0, ..., typename Fn-1>
+ std::pair<bool,std::size_t> conc_join_any_until(
+ const system_time& wait_until, F0 f0, ..., Fn fn-1);
+ template<typename TimeDuration, typename F0, ..., typename Fn-1>
+ std::pair<bool,std::size_t> conc_join_all_for(
+ TimeDuration wait_for, F0 f0, ..., Fn fn-1);
-[section:thread_tuple_join_first_then_interrupt Non Member Function `thread_join_first_then_interrupt()`]
+[section:conc_join_any Non Member Function `conc_join_any()`]
[/==========================================================================================]
template<typename F0, ..., typename Fn-1>
- std::size_t thread_join_first_then_interrupt(F0 f0, ..., Fn fn-1);
+ std::size_t conc_join_any(F0 f0, ..., Fn fn-1);
[variablelist
@@ -1481,14 +2473,27 @@
[endsect]
-[section:thread_tuple_timed_join_first_then_interruptl Non Member Function `thread_timed_join_first_then_interrupt()`]
+[section:conc_join_any_until Non Member Function `conc_join_any_until()`]
[/==========================================================================================]
template<typename F0, ..., typename Fn-1>
- std::pair<bool,std::size_t> thread_timed_join_first_then_interrupt(
+ std::pair<bool,std::size_t> conc_join_any_until(
const system_time& wait_until, F0 f0, ..., Fn fn-1);
+
+[variablelist
+
+[[Effects:] [launch in each function on a thread of execution, join the first and then interrupt the others or interrup all.]]
+[[Returns:] [a pair consisting of a boolean stating if the a thread has been joined before the given time and the index on the tuple of the first thread joined.]]
+
+]
+
+[endsect]
+
+[section:conc_join_any_for Non Member Function `conc_join_any_for()`]
+[/==========================================================================================]
+
template<typename TimeDuration, typename F0, ..., typename Fn-1>
- std::pair<bool,std::size_t> thread_timed_join_first_then_interrupt(
+ std::pair<bool,std::size_t> conc_join_any_for(
TimeDuration wait_for, F0 f0, ..., Fn fn-1);
[variablelist
@@ -1500,6 +2505,7 @@
[endsect]
+
[endsect]
[section:thread_group_once_hpp Header `<boost/interthreads/thread_group_once.hpp>`]
@@ -1539,29 +2545,24 @@
void swap(thread_group_once<n>& x);
- // bool joinable() const;
- void join();
+ bool joinables() const;
+
void join_all();
- // bool timed_join(const system_time& wait_until);
- // template<typename TimeDuration>
- // bool timed_join(TimeDuration const& rel_time);
- // bool timed_join_all(const system_time& wait_until);
- // template<typename TimeDuration>
- // bool timed_join_all(TimeDuration const& rel_time);
+ bool join_all_until(const system_time& wait_until);
+ template<typename TimeDuration>
+ bool join_all_for(TimeDuration const& rel_time);
- std::size_t join_first_then_interrupt();
- std::pair<bool,std::size_t> timed_join_first_then_interrupt(
+ std::size_t join_any();
+ std::pair<bool,std::size_t> join_any_until(
const system_time& wait_until);
template<typename TimeDuration>
- std::pair<bool,std::size_t> timed_join_first_then_interrupt(
+ std::pair<bool,std::size_t> join_any_for(
TimeDuration const& rel_time);
- // void detach();
- // void detach_all();
+ void detach_all();
- void interrupt();
void interrupt_all();
- // bool interruption_requested() const;
+ bool interruption_requested() const;
size_t size();
@@ -1603,10 +2604,10 @@
[endsect]
-[section:thread_group_once_joinable Member function `joinable()`]
+[section:thread_group_once_joinable Member function `joinables()`]
[/==========================================================================================]
- bool joinable() const;
+ bool joinables() const;
[variablelist
@@ -1618,10 +2619,9 @@
[endsect]
-[section:thread_group_once_join Member function `join()|join_all()`]
+[section:thread_group_once_join Member function `join_all()`]
[/==========================================================================================]
- void join();
void join_all();
[variablelist
@@ -1638,16 +2638,12 @@
[endsect]
-[section:thread_group_once_timed_join Member function `timed_join()|timed_join_all()`]
+[section:thread_group_once_timed_join Member function `join_all_until()`]
[/==========================================================================================]
- bool timed_join(const system_time& wait_until);
- template<typename TimeDuration>
- bool timed_join(TimeDuration const& rel_time);
-
- bool timed_join_all(const system_time& wait_until);
+ bool join_all_until(const system_time& wait_until);
template<typename TimeDuration>
- bool timed_join_all(TimeDuration const& rel_time);
+ bool join_all_for(TimeDuration const& rel_time);
[variablelist
@@ -1665,37 +2661,37 @@
[endsect]
-[section:join_first_then_interrupt Member function `join_first_then_interrupt()`]
+[section:join_first_then_interrupt Member function `join_any()`]
[/==========================================================================================]
- std::size_t join_first_then_interrupt();
+ std::size_t join_any();
[variablelist
-[[Effects:] [Call `join_first()` and the `interrup_all()`.]]
+[[Effects:] [Call `join_any()` and the `interrup_all()`.]]
[[Postcondition:] [Every thread in the group has terminated.]]
[[Throws:] [Nothing]]
-[[Note:] [Since `boost::thread::join` is one of the predefined interruption points, `thread_group_once<>::join_all()` is also an interruption point.]]
+[[Note:] [Since `join_any` is one of the predefined interruption points, `thread_group_once<>::join_any()` is also an interruption point.]]
]
[endsect]
-[section:timed_join_first_then_interrupt Member function `timed_join_first_then_interrupt()`]
+[section:timed_join_first_then_interrupt Member function `join_any_until()`]
[/==========================================================================================]
- std::pair<bool,std::size_t> timed_join_first_then_interrupt(
+ std::pair<bool,std::size_t> join_any_until(
const system_time& wait_until);
template<typename TimeDuration>
- std::pair<bool,std::size_t> timed_join_first_then_interrupt(
+ std::pair<bool,std::size_t> join_any_for(
TimeDuration const& rel_time);
[variablelist
-[[Effects:] [Call `timed_join_first()` and the `interrup_all()`.]]
+[[Effects:] [Call `get_until()` and the `interrup_all()`.]]
[[Postcondition:] [Every thread in the group has terminated.]]
@@ -1709,10 +2705,9 @@
[endsect]
-[section:detach_all Member function `detach|detach_all()`]
+[section:detach_all Member function `detach_all()`]
[/==========================================================================================]
- void detach();
void detach_all();
[variablelist
@@ -1723,10 +2718,9 @@
[endsect]
-[section:thread_group_once_interrupt_all Member function `interrupt()|interrupt_all()`]
+[section Member function `interrupt_all()`]
[/==========================================================================================]
- void interrupt();
void interrupt_all();
[variablelist
Modified: sandbox/interthreads/libs/interthreads/doc/tutorial.qbk
==============================================================================
--- sandbox/interthreads/libs/interthreads/doc/tutorial.qbk (original)
+++ sandbox/interthreads/libs/interthreads/doc/tutorial.qbk 2009-01-04 13:01:47 EST (Sun, 04 Jan 2009)
@@ -73,7 +73,7 @@
* explicitly on the curret thread. Basically it works like a thread local storage from inside the thread.
bith::thread_specific_shared_ptr<myclass> ptr;
-
+ void func() {
{ // current thread
// ...
ptr.reset(p);
@@ -83,40 +83,81 @@
* When we associate a thread decoration to the thread_specific_shared_ptr<> we can initialize all the decorations either calling
decorate or creating a thread wrapping the function with the thread thread_decorator functor.
+ bith::thread_specific_shared_ptr<myclass> ptr;
void myclass_init() {
ptr.reset(new myclass(any specific parameters));
}
- bith::thread_decoratio myclass_decoration(myclass_init);
+ bith::thread_decoration myclass_decoration(myclass_init);
+
+ void func() {
+ { // current thread
+ // ...
+ ptr.reset(p);
+ // ...
+ }
+
+ boost::thread th=bith::make_decorated_thread(func);
[endsect]
[section Obtain the pointer to the thread-specific object on the current thread]
[/==========================================================================================]
-All functions known from boost::thread_specific_ptr are available, and so its semantics from inside the thread.
+All functions known from boost::thread_specific_ptr are available except release, and so its
+semantics from inside the thread.
The value for the current thread can be obtained using the `get()` member function, or by using
the `*` and `->` pointer deference operators.
-[endsect]
+ void func() {
+ { // current thread
+ // ...
+ if (ptr.get()==0) ptr.reset(new myclass);
+ // ...
+ ptr->someFct();
+ }
-[section Waiting for the seeting of the thread-specific object from another thread]
-[/==========================================================================================]
-The setting of a thread specific context must be done on a thread. When access the thread specific shared context of another thread it can be NULL.
-The library provides a wait_and_get() function that allows a thread tosynchonize with the setting from another thread.
+[endsect]
- shared_ptr<myclass> shp = ptr.wait_and_get(th->get_id());
-
-where `th` is a `boost::thread*`.
[section Obtain the pointer to the thread-specific object of another thread]
[/==========================================================================================]
Besides this another thread can get access to the data when it can get the thread::id by:
+ boost::thread th=bith::make_decorated_thread(func);
+
+ ptr[th->get_id()]->foo();
+
+where `foo()` is a function of `myclass`.
+
+This could work or not. the issue apears as we can get a reference to a thread before the threads has started,
+so the setting of the threads specific context could be not done yet. One way to manage with this error is to
+get the shared pointer and check if it contains something or not.
+
+
shared_ptr<myclass> shp = ptr[th->get_id()]->foo();
+ if (shp.get() != 0) shp->foo();
+ else ...
+
+When we need this we can pool:
+
+ shared_ptr<myclass> shp;
+ do {
+ shp = ptr[th->get_id()]->foo();
+ } while(shp.get() == 0);
+ shp->foo();
+
+
+The library provides a synchonization mechanism to solve this issue.
+The wait_and_get() function allows a thread to synchronize with the setting from another thread.
+
+ shared_ptr<myclass> shp = ptr.wait_and_get(th->get_id());
+ shp->foo();
+or
+
+ ptr.wait_and_get(th->get_id()->foo();
-where `th` is a `boost::thread*` and `foo()` is a function of `myclass`.
The lifetime of the myclass instance is managed by a shared_ptr. One reference is held by the thread (by means of a tss), a second is
held by the thread::id to shared_ptr<T> map and additional references might be held by other threads that obtained it by `*pmyclass[th]`.
@@ -629,4 +670,4 @@
[endsect]
-[endsect]
+[endsect]
\ No newline at end of file
Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk