|
Boost-Commit : |
Subject: [Boost-commit] svn:boost r53351 - sandbox/task/libs/task/doc
From: oliver.kowalke_at_[hidden]
Date: 2009-05-28 13:41:30
Author: olli
Date: 2009-05-28 13:41:28 EDT (Thu, 28 May 2009)
New Revision: 53351
URL: http://svn.boost.org/trac/boost/changeset/53351
Log:
* documentation
Added:
sandbox/task/libs/task/doc/ref_meta_functions.qbk (contents, props changed)
Text files modified:
sandbox/task/libs/task/doc/boost_task.qbk | 16 ++++
sandbox/task/libs/task/doc/default_pool.qbk | 40 +++++++++++
sandbox/task/libs/task/doc/forkjoin.qbk | 131 +++++++++++++--------------------------
sandbox/task/libs/task/doc/introduction.qbk | 6
sandbox/task/libs/task/doc/meta_functions.qbk | 20 +++---
sandbox/task/libs/task/doc/new_thread.qbk | 2
sandbox/task/libs/task/doc/overview.qbk | 4
sandbox/task/libs/task/doc/processor_binding.qbk | 14 ++-
sandbox/task/libs/task/doc/reference.qbk | 4
sandbox/task/libs/task/doc/scheduler.qbk | 119 ++++++++++++++++++++++++-----------
sandbox/task/libs/task/doc/shutdown.qbk | 119 +++++++++++++++++++++++++++++-------
sandbox/task/libs/task/doc/utilities.qbk | 45 ++++++++++++-
sandbox/task/libs/task/doc/work_stealing.qbk | 34 ++++++---
13 files changed, 361 insertions(+), 193 deletions(-)
Modified: sandbox/task/libs/task/doc/boost_task.qbk
==============================================================================
--- sandbox/task/libs/task/doc/boost_task.qbk (original)
+++ sandbox/task/libs/task/doc/boost_task.qbk 2009-05-28 13:41:28 EDT (Thu, 28 May 2009)
@@ -36,6 +36,7 @@
[template link_work_stealing[link_text] [link boost_task.async_executor.pool.work_stealing [link_text]]]
[def __thread__ `boost::thread`]
+[def __thread_id__ `boost::thread::id`]
[def __hardware_concurrency__ `boost::thread::hardware_concurrency()`]
@@ -44,16 +45,25 @@
[def __default_pool__ `boost::task::default_pool`]
[def __dynamic_pool__ `boost::task::dynamic_pool`]
[def __handle__ `boost::task::handle`]
+[def __hase_priority__ `boost::task::has_priority`]
[def __hwm__ `boost::task::high_watermark`]
+[def __id__ `boost::task::id`]
[def __lwm__ `boost::task::low_watermark`]
[def __new_thread__ `boost::task::new_thread`]
[def __own_thread__ `boost::task::own_thread`]
-[def __task__ `boost::task::task`]
-[def __task_interrupted__ `boost::task::task_interrupted`]
+[def __pool_size__ `boost::task::poolsize`]
+[def __priority__ `boost::task::priority`]
+[def __priority_type__ `boost::task::priority_type`]
+[def __replace_oldest__ `boost::task::replace_oldest`]
[def __static_pool__ `boost::task::static_pool`]
[def __system_time__ `boost::task::system_time`]
+[def __take_oldest__ `boost::task::take_oldest`]
+[def __task__ `boost::task::task`]
+[def __task_interrupted__ `boost::task::task_interrupted`]
[def __unbounded_channel__ `boost::task::unbounded_channel`]
+[def __full_default_pool__ `boost::task::static_pool< boost::task::unbounded_channel< boost::task::fifo > >`]
+
[def __fn_delay__ `boost::this_task::delay()`]
[def __fn_get_pool__ `boost::this_task::get_pool()`]
[def __fn_tt_interrupt__ `boost::this_task::interrupt()`]
@@ -84,6 +94,8 @@
[def __fn_operator__ `operator()()`]
[def __fn_pending__ `pending()()`]
[def __fn_size__ size()`]
+[def __fn_shutdown__ shutdown()`]
+[def __fn_shutdown_now__ shutdown_now()`]
[def __fn_wait__ `wait()`]
[def __fn_wait_for__ `wait_for()`]
[def __fn_wait_until__ `wait_until()`]
Modified: sandbox/task/libs/task/doc/default_pool.qbk
==============================================================================
--- sandbox/task/libs/task/doc/default_pool.qbk (original)
+++ sandbox/task/libs/task/doc/default_pool.qbk 2009-05-28 13:41:28 EDT (Thu, 28 May 2009)
@@ -8,9 +8,43 @@
[section:default_pool Default pool]
-The free function `boost::tp::get_default_pool()` returns a reference to the default __threadpool__ instance. The default __threadpool__ is
-of type `boost::tp::pool< boost::tp::unbounded_channel< boost::tp::fifo > >` and will contain as many __worker_threads__ as
-`boost::thread::hardware_concurrency()` returns.
+The library provides a default-pool accessible via __fn_default_pool__. The function returns a reference to __full_default_pool__. The static instance of __default_pool__ contains as many __worker_threads__ as
+__hardware_concurrency__ returns, queues unlimited amount of __tasks__ and schedules the __tasks__ in FIFO-order.
+
+
+``
+ long fibonacci_fn( long n)
+ {
+ if ( n == 0) return 0;
+ if ( n == 1) return 1;
+ long k1( 1), k2( 0);
+ for ( int i( 2); i <= n; ++i)
+ {
+ long tmp( k1);
+ k1 = k1 + k2;
+ k2 = tmp;
+ }
+ return k1;
+ }
+
+ void main()
+ {
+ std::cout << "worker-threads running in default-pool == " << boost::task::default_pool().size() << "\n";
+
+ boost::task::handle< long > h1(
+ boost::task::async(
+ boost::task::default_pool(), // asynchronous executor == default-pool
+ boost::task::make_task( fibonacci_fn, 10) ) );
+
+ boost::task::handle< long > h2(
+ boost::task::async(
+ boost::task::default_pool(), // asynchronous executor == default-pool
+ boost::task::make_task( fibonacci_fn, 5) ) );
+
+ std::cout << "fibonacci(10) == " << h1.get() << "\n";
+ std::cout << "fibonacci(5) == " << h2.get() << std::endl;
+ }
+``
[endsect]
Modified: sandbox/task/libs/task/doc/forkjoin.qbk
==============================================================================
--- sandbox/task/libs/task/doc/forkjoin.qbk (original)
+++ sandbox/task/libs/task/doc/forkjoin.qbk 2009-05-28 13:41:28 EDT (Thu, 28 May 2009)
@@ -8,99 +8,58 @@
[section:forkjoin Fork/Join]
-Fork/Join algorithms are recursive divide-and-conquer algorithms which repeatedly splitt __sub_actions__ until they become small enough to solve using simple, short sequential methods, so that they run in parallel on multiple cores.
+Fork/Join algorithms are recursive divide-and-conquer algorithms which repeatedly splitt __sub_taskss__ until they become small enough to solve using simple, short sequential methods,
+so that they run in parallel on multiple cores.
-The fork operation creates a new __sub_action__ (which can run in parallel) in the pool. The current __actions__ is not proceeded in the join operation until the forked __sub_actions__ have completed. In the meantime the __worker_thread__ executes other __actions__ from its local __worker_queue__.
+The fork operation creates new __sub_tasks__ which can run in parallel. The current __task__ is not proceeded in the join operation until the forked __sub_tasks__ have completed.
+In the meantime the __worker_thread__ executes other __tasks__ from its local worker-queue.
- // defines the threadpool type
- namespace pt = boost::posix_time;
- namespace tp = boost::tp;
-
- typedef tp::pool< tp::unbounded_channel< tp::fifo > > pool_type;
-
- class fibo
+``
+ long serial_fib( long n)
{
- private:
- int offset_;
-
- int seq_( int n)
- {
- if ( n <= 1) return n;
- else return seq_( n - 2) + seq_( n - 1);
- }
-
- int par_( int n)
- {
- if ( n <= offset_) return seq_( n);
- else
- {
- tp::task< int > t1(
- boost::this_task::get_thread_pool< pool_type >().submit(
- boost::bind(
- & fibo::par_,
- boost::ref( * this),
- n - 1) ) );
- tp::task< int > t2(
- boost::this_task::get_thread_pool< pool_type >().submit(
- boost::bind(
- & fibo::par_,
- boost::ref( * this),
- n - 2) ) );
- return t1.result().get() + t2.result().get();
- }
- }
-
- public:
- fibo( int offset)
- : offset_( offset)
- {}
-
- int execute( int n)
- {
- int result( par_( n) );
- return result;
- }
- };
-
- int main( int argc, char *argv[])
+ if( n < 2) return n;
+ else return serial_fib( n - 1) + serial_fib( n - 2);
+ }
+
+ long parallel_fib( long n, long cutof)
{
- try
+ if ( n < cutof) return serial_fib( n);
+ else
{
- pool_type pool( tp::poolsize( 3) );
- fibo fib( 5);
- std::vector< tp::task< int > > results;
- results.reserve( 40);
-
- pt::ptime start( pt::microsec_clock::universal_time() );
-
- for ( int i = 0; i < 32; ++i)
- results.push_back(
- pool.submit(
- boost::bind(
- & fibo::execute,
- boost::ref( fib),
- i) ) );
-
- int k = 0;
- std::vector< tp::task< int > >::iterator e( results.end() );
- for (
- std::vector< tp::task< int > >::iterator i( results.begin() );
- i != e;
- ++i)
- std::cout << "fibonacci " << k++ << " == " << i->result().get() << std::endl;
-
- pt::ptime stop( pt::microsec_clock::universal_time() );
- std::cout << ( stop - start).total_milliseconds() << " milli seconds" << std::endl;
-
- return EXIT_SUCCESS;
+ // fork a sub-task calculating fibonacci(n-1)
+ h1 = boost::task::async(
+ boost::task::as_sub_task(),
+ boost::task::make_task(
+ parallel_fib,
+ n - 1,
+ cutof) );
+ // fork a sub-task calculating fibonacci(n-2)
+ h2 = boost::task::async(
+ boost::task::as_sub_task(),
+ boost::task::make_task(
+ parallel_fib,
+ n - 2,
+ cutof) );
+ // join the results of both sub-tasks
+ // if one of the both sub-tasks is not ready
+ // the worker-thread does not block, it executes other
+ // task from its local-queue
+ return h1.get() + h2.get();
}
- catch ( std::exception const& e)
- { std::cerr << "exception: " << e.what() << std::endl; }
- catch ( ... )
- { std::cerr << "unhandled" << std::endl; }
-
- return EXIT_FAILURE;
}
+ void main()
+ {
+ boost::task::handle< long > h( // handle for fibonacci calculation
+ boost::task::async(
+ boost::task::default_pool(), // access the default thread-pool
+ boost::task::make_task( // calculate fibonacci number 10
+ parallel_fib, // for numbers < 5 do inline recursive calculation
+ 10,
+ 5) ) );
+ std::cout << h.get() << std::endl;
+ }
+``
+
[endsect]
Modified: sandbox/task/libs/task/doc/introduction.qbk
==============================================================================
--- sandbox/task/libs/task/doc/introduction.qbk (original)
+++ sandbox/task/libs/task/doc/introduction.qbk 2009-05-28 13:41:28 EDT (Thu, 28 May 2009)
@@ -91,21 +91,21 @@
if ( n < cutof) return serial_fib( n);
else
{
- // submit a sub-task to pool calculating fibonacci(n-1)
+ // fork a sub-task calculating fibonacci(n-1)
h1 = boost::task::async(
boost::this_task::get_pool(),
boost::task::make_task(
parallel_fib,
n - 1,
cutof) );
- // submit a sub-task to pool calculating fibonacci(n-2)
+ // fork a sub-task calculating fibonacci(n-2)
h2 = boost::task::async(
boost::this_task::get_pool(),
boost::task::make_task(
parallel_fib,
n - 2,
cutof) );
- // calculate fibonacci(n) from the results of both sub-tasks
+ // join the results of both sub-tasks
return h1.get() + h2.get();
}
}
Modified: sandbox/task/libs/task/doc/meta_functions.qbk
==============================================================================
--- sandbox/task/libs/task/doc/meta_functions.qbk (original)
+++ sandbox/task/libs/task/doc/meta_functions.qbk 2009-05-28 13:41:28 EDT (Thu, 28 May 2009)
@@ -8,18 +8,18 @@
[section:meta_functions Meta functions]
-If the __threadpool__ supports priorities `boost::tp::has_priority< pool_type >` evaluates to `true`. The priority type is determined by `boost::tp::priority_type< pool_type >`.
+If the __thread_pool__ supports priorities __hase_priority__ evaluates to `true` at compile-time. The type of the priority is determined by __priority_type__.
- typedef boost::tp::pool<
- boost::tp::unbounded_channel< boost::tp::priority< int > >
- > pool_type;
- std::cout << std::boolalpha << boost::tp::has_priority< pool_type >::value << std::endl;
- std::cout << typeid( boost::tp::priority_type< pool_type >::type).name() << std::endl;
-
-The support of fibers can be tested with meta-function `boost::tp::has_fibers< pool_type >`.
-
- std::cout << std::boolalpha << boost::tp::has_fibers< pool_type >::value << std::endl;
+``
+ typdef boost::task::static_pool<
+ boost::task::unbounded_channel<
+ boost::task::priority< int > > // pool with priority scheduling; integer as priority type
+ > pool_type;
+
+ std::cout << std::boolalpha << boost::task::has_priority< pool_type >::value << "\n";
+ std::cout << typeid( boost::task::priority_type< pool_type >::type).name() << std::endl;
+``
[endsect]
Modified: sandbox/task/libs/task/doc/new_thread.qbk
==============================================================================
--- sandbox/task/libs/task/doc/new_thread.qbk (original)
+++ sandbox/task/libs/task/doc/new_thread.qbk 2009-05-28 13:41:28 EDT (Thu, 28 May 2009)
@@ -12,7 +12,7 @@
[caution Always store the returned __act__ in a variable because __handle__ joins the thread in its destructor (if the last reference gets out of scope). ]
-Points of [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2802.html N2802] should be addressed.
+The topic of [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2802.html N2802] should be addressed.
``
long fibonacci( long n)
Modified: sandbox/task/libs/task/doc/overview.qbk
==============================================================================
--- sandbox/task/libs/task/doc/overview.qbk (original)
+++ sandbox/task/libs/task/doc/overview.qbk 2009-05-28 13:41:28 EDT (Thu, 28 May 2009)
@@ -41,7 +41,9 @@
* N2802: A plea to reconsider detach-on-destruction for thread objects [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2802.html] written by Hans-J. Boehm.
-* C++task-force mailing list
+* mailing list C++task-force
+
+* [@http://herbsutter.wordpress.com 'Sutterâs Mill'] by Herb Sutter
[note __boost_task__ uses __boost_future__ from Anthony Williams (will be integrated in some of the next releases of __boost__thread__).]
Modified: sandbox/task/libs/task/doc/processor_binding.qbk
==============================================================================
--- sandbox/task/libs/task/doc/processor_binding.qbk (original)
+++ sandbox/task/libs/task/doc/processor_binding.qbk 2009-05-28 13:41:28 EDT (Thu, 28 May 2009)
@@ -8,14 +8,16 @@
[section:processor_binding Processor binding]
-For some applications it is convenient to bind the worker threads of the pool to processors of the system. For this purpose BOOST_BIND_WORKER_TO_PROCESSORS must be defined. Without the poolsize in the construtor the __threadpool__ will contain as many
-__worker_threads__ as processors (== __hardware_concurrency__) are available and each __worker_thread__ is bound to one processor.
+For some applications it is convenient to bind the __worker_threads__ to processors of the system. For this purpose BOOST_HAS_PROCESSOR_BINDINGS must be defined so that for each core a
+__worker_thread__ is created an bound the the core. __pool_size__ must not be given to the constructor.
- boost::tp::pool<
- boost::tp::unbounded_channel< boost::tp::fifo >
- > pool;
+``
+ boost::task::static_pool<
+ boost::task::unbounded_channel< boost::tp::fifo >
+ > pool; // constructs thread-pool with worker-threads as hardware_concurrency() returns
+``
-The code above will create a pool with two __worker_threads__ on a dual core system (each bound to one core).
+The constructor takes additional arguments for the link_work_stealing[work-stealing algorithm] and link_channel[high-] and link_channel[low-watermark] too.
[endsect]
Added: sandbox/task/libs/task/doc/ref_meta_functions.qbk
==============================================================================
--- (empty file)
+++ sandbox/task/libs/task/doc/ref_meta_functions.qbk 2009-05-28 13:41:28 EDT (Thu, 28 May 2009)
@@ -0,0 +1,36 @@
+[/
+ (C) Copyright 2008 Oliver Kowalke.
+ 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:has_priority Meta function `has_priority`]
+
+ #include <boost/tp/info.hpp>
+
+ template< typename Pool >
+ struct has_priority
+ :
+ public mpl::bool_<
+ is_same<
+ detail::has_priority,
+ typename Pool::scheduler_type::priority_tag_type
+ >::value
+ >
+ {};
+
+[endsect]
+
+
+[section:priority_type Meta function `priority_type`]
+
+ #include <boost/tp/info.hpp>
+
+ template< typename Pool >
+ struct priority_type
+ {
+ typedef typename Pool::scheduler_type::attribute_type type;
+ };
+
+[endsect]
Modified: sandbox/task/libs/task/doc/reference.qbk
==============================================================================
--- sandbox/task/libs/task/doc/reference.qbk (original)
+++ sandbox/task/libs/task/doc/reference.qbk 2009-05-28 13:41:28 EDT (Thu, 28 May 2009)
@@ -8,10 +8,10 @@
[section:reference Reference]
-[include ref_async.qbk]
-[include ref_static_pool.qbk]
[include ref_task.qbk]
[include ref_handle.qbk]
+[include ref_async.qbk]
+[include ref_static_pool.qbk]
[include ref_utilities.qbk]
[include ref_meta_functions.qbk]
[include ref_exceptions.qbk]
Modified: sandbox/task/libs/task/doc/scheduler.qbk
==============================================================================
--- sandbox/task/libs/task/doc/scheduler.qbk (original)
+++ sandbox/task/libs/task/doc/scheduler.qbk 2009-05-28 13:41:28 EDT (Thu, 28 May 2009)
@@ -18,16 +18,44 @@
[heading priority]
-Each pending task is associated with a priority attribute which is used for ordering __actions__.
+Each __task__ is submitted to the pool with a priority attribute. The type and ordering of the priority is user-defined.
+
+``
+ boost::task::static_pool<
+ boost::task::unbounded_channel< // allow unlimited tasks to be queue in global-queue
+ boost::task::priority< int > > // tasks with lower priority are scheduled first
+ > pool( boost::task::poolsize( 5) );
+
+ boost::task::async(
+ pool, // thread-pool
+ boost::task::make_task( some_fn), // task to be executed
+ 5); // priority is 5
+
+ boost::task::async(
+ pool, // thread-pool
+ boost::task::make_task( another_fn), // task to be executed
+ 3); // priority is 3
+``
+
+In this example the __tasks__ get scheduled by the assigned integer (third argument of __fn_async__). The __task__ with the lowest priority
+gets scheduled first (taken by a __worker_thread__). The ordering can be changed by the second argument of __priority__ (the default is `std::less< Attr >`).
+
+``
+ boost::task::static_pool<
+ boost::task::unbounded_channel<
+ boost::task::priority< int, std::greater< int > > > // tasks with higher priority are scheduled first
+
+ > pool( boost::task::poolsize( 5) );
+``
[heading smart]
-Each pending __actions__ is associated with an attribute. The scheduler gets an put- and take-policy
-as template arguments. The corresponding policy get applied for each insertion and removal.
+Each inserted __task__ is associated with an attribute. The scheduler gets an put- and take-policy
+as template arguments. The corresponding policy gets applied for each insertion and removal.
-__boost_task__ provides ['boost::tp::replace_oldest] as put policy and ['boost::tp::take_oldest] as take
-policy. Both policies allow the replacement of old __actions__ in the scheduler by new ones.
+__boost_task__ provides __replace_oldest__ as put- policy and __take_oldest__ as take-policy.
+Both policies allow the replacement of older (pending) __tasks__ in the scheduler by new ones.
// creates a pool with unbounded channel
// tasks are processed depending on the associated attributed
@@ -35,40 +63,53 @@
// will be replaced by the new task
// this example would execute add( 1, 2) and add( 5, 6)
// add( 2, 3) is removed (if pending when add( 5, 6) is submitted)
- boost::tp::pool<
- boost::tp::unbounded_channel<
- boost::tp::smart<
- int,
- std::less< int >,
- boost::tp::replace_oldest,
- boost::tp::take_oldest
- >
- >
- > pool( boost::tp::poolsize( 1) );
-
- pool.submit(
- boost::bind(
- add_fn,
- 1,
- 2),
- 0);
-
- // replaced by later task with same attribute
- // if still pending in pool
- pool.submit(
- boost::bind(
- add_fn,
- 3,
- 4),
- 1);
-
- // will replace previous pending action
- pool.submit(
- boost::bind(
- add_fn,
- 5,
- 6),
- 1);
+
+``
+ long fibonacci_fn( long n)
+ {
+ if ( n == 0) return 0;
+ if ( n == 1) return 1;
+ long k1( 1), k2( 0);
+ for ( int i( 2); i <= n; ++i)
+ {
+ long tmp( k1);
+ k1 = k1 + k2;
+ k2 = tmp;
+ }
+ return k1;
+ }
+
+ typedef boost::task::static_pool<
+ boost::task::unbounded_channel<
+ boost::task::smart<
+ int,
+ std::less< int >,
+ boost::task::replace_oldest,
+ boost::task::take_oldest
+ >
+ >
+ > pool_type;
+
+ void main()
+ {
+ pool_type pool( boost::task::poolsize( 1) );
+
+ ...
+
+ // replaced by later task with same attribute == 2
+ // if still pending in pool
+ boost::task::async(
+ pool,
+ boost::task::make_task( fibonacci_fn, 10),
+ 2); // attribute is 2
+
+ // will replace previous pending task with attribute == 2
+ boost::task::async(
+ pool,
+ boost::task::make_task( fibonacci_fn, 5),
+ 2); // attribute is 2 too
+ }
+``
[endsect]
Modified: sandbox/task/libs/task/doc/shutdown.qbk
==============================================================================
--- sandbox/task/libs/task/doc/shutdown.qbk (original)
+++ sandbox/task/libs/task/doc/shutdown.qbk 2009-05-28 13:41:28 EDT (Thu, 28 May 2009)
@@ -6,40 +6,113 @@
]
-[section:static_pool Pool shutdown]
+[section:pool_shutdown Pool shutdown]
-[heading Shutdown]
+__boost_task__ allows to shutdown a __thread_pool__ explicitly via functions __fn_shutdown__ and __fn_shutdown_now__.
+The destructor of the pool calls __fn_shutdown__ if not already done so that all __worker_threads__ are joined and the topic of
+[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2802.html N2802] should be addressed.
-If `boost::tp::pool< Channel >::shutdown()` is called - the the pool is set closed and all __worker_threads__ are joined until all pending __actions__ are processed. No futher __actions__ can be submitted by application threads.
+[heading Shutdown]
-[note The deconstructor calls `boost::tp::pool< Channel >::shutdown()` if the pool was not shutdown yet.]
+If __fn_shutdown__ is called - the the pool is set the closed state and all __worker_threads__ are joined until all pending __tasks__ are processed.
+No futher __tasks__ can be submitted.
- boost::tp::pool<
- boost::tp::unbounded_channel< boost::tp::fifo >
- > pool( boost::tp::poolsize( 1) );
-
- boost::tp::task< int > t1(
- pool.submit(
- boost::bind(
- fibonacci_fn,
- 10) ) );
- boost::tp::task< int > t2(
- pool.submit(
- boost::bind(
- fibonacci_fn,
- 10) ) );
+[note The deconstructor calls __fn_shutdown__ if the pool was not shutdown yet.]
- pool.shutdown();
- std::cout << t1.result().get() << std::endl; // 55
- std::cout << t2.result().get() << std::endl; // 55
+``
+ long fibonacci_fn( long n)
+ {
+ if ( n == 0) return 0;
+ if ( n == 1) return 1;
+ long k1( 1), k2( 0);
+ for ( int i( 2); i <= n; ++i)
+ {
+ long tmp( k1);
+ k1 = k1 + k2;
+ k2 = tmp;
+ }
+ return k1;
+ }
+
+ typedef boost::task::static_pool<
+ boost::task::unbounded_channel<
+ boost::task::fifo
+ >
+ > pool_type;
+
+ void main()
+ {
+ pool_type pool( boost::task::poolsize( 1) );
+
+ ...
+
+ boost::task::handle< long > h1(
+ boost::task::async(
+ pool, // asynchronous executor
+ boost::task::make_task( fibonacci_fn, 10) ) );
+
+ boost::task::handle< long > h2(
+ boost::task::async(
+ pool, // asynchronous executor
+ boost::task::make_task( fibonacci_fn, 5) ) );
+
+ pool.shutdown();
+
+ std::cout << "fibonacci(10) == " << h1.get() << "\n";
+ std::cout << "fibonacci(5) == " << h2.get() << std::endl;
+ }
+``
[heading Shutdown immediatly]
-The function `boost::tp::pool< Channel >::shutdown_now()` closes the pool, interrupts and then joins all __worker_threads__. All pending (unprocessed) __actions__ will be returned.
+The function __fn_shutdown_now__ closes the pool, interrupts and then joins all __worker_threads__. Pending __tasks__ are unprocessed.
+
-[important Pending __actions__ in the local __worker_queues__ are not returned if `boost::tp::pool< Channel >::shutdown_now()` was called.]
+``
+ long fibonacci_fn( long n)
+ {
+ if ( n == 0) return 0;
+ if ( n == 1) return 1;
+ long k1( 1), k2( 0);
+ for ( int i( 2); i <= n; ++i)
+ {
+ long tmp( k1);
+ k1 = k1 + k2;
+ k2 = tmp;
+ }
+ return k1;
+ }
+
+ typedef boost::task::static_pool<
+ boost::task::unbounded_channel<
+ boost::task::fifo
+ >
+ > pool_type;
+
+ void main()
+ {
+ pool_type pool( boost::task::poolsize( 1) );
+
+ ...
+
+ boost::task::handle< long > h1(
+ boost::task::async(
+ pool, // asynchronous executor
+ boost::task::make_task( fibonacci_fn, 10) ) );
+
+ boost::task::handle< long > h2(
+ boost::task::async(
+ pool, // asynchronous executor
+ boost::task::make_task( fibonacci_fn, 5) ) );
+
+ pool.shutdown_now();
+
+ std::cout << "fibonacci(10) == " << h1.get() << "\n"; // may throw broken_task or task_interrupted
+ std::cout << "fibonacci(5) == " << h2.get() << std::endl; // may throw broken_task or task_interrupted
+ }
+``
[endsect]
Modified: sandbox/task/libs/task/doc/utilities.qbk
==============================================================================
--- sandbox/task/libs/task/doc/utilities.qbk (original)
+++ sandbox/task/libs/task/doc/utilities.qbk 2009-05-28 13:41:28 EDT (Thu, 28 May 2009)
@@ -6,14 +6,49 @@
]
-[section:this_task Namespace this_task]
+[section:utilities Utilities]
+
+__boost_task__ provides some free-functions which can be used inside a __task__ to access some informations (like if the __task__
+runs in a __thread_pool__).
+
+
+[heading reschedule_until]
In the function `boost::this_task::reschedule_until( Pred const&)` allows to synchronize the task with other
-asynchronous events without blocking the __worker_threads__ (bool Pred::operator()() must not block)
+asynchronous events without blocking the __worker_threads__ (bool Pred::operator()() must not block).
The current task will be rescheduled until the passed predicate becomes true.
-The pool can be accessed via `boost::this_task::get_thread_pool< Pool >()` if the calling code is executed by a __worker_thread__.
-`boost::this_task::s_worker()` evaluates true if the current thread is __worker_thread__ and `boost::this_task::worker_id()`
-returns the thread id.
+
+
+[heading get_pool]
+
+The pool in which the current code (__task__) is executed can be accessed via __fn_get_pool__. If hte code is not executed by
+a __worker_thread__ an assertion is raised.
+
+
+[heading runs_in_pool]
+
+In order to check if the current code is executed in a __thread_pool__ __fn_runs_in_pool__ should be used.
+
+
+[heading worker_id]
+
+__fn_worker_id__ returns the __thread_id__ of the __worker_thread__ executing the current __task__.
+
+
+[heading delay]
+
+The execution of a __task__ can be delayed for a time-duration or until a specific time-point with __fn_delay__.
+
+
+[heading yield]
+
+If a __task__ detects that it would bould block it can yield itself with __fn_yield__ so that the __worker_thread__ can execute
+another __task__ in the meantime.
+
+
+[heading interrupt]
+
+A __task__ can interrupt itself via __fn_tt_interrupt__.
[endsect]
Modified: sandbox/task/libs/task/doc/work_stealing.qbk
==============================================================================
--- sandbox/task/libs/task/doc/work_stealing.qbk (original)
+++ sandbox/task/libs/task/doc/work_stealing.qbk 2009-05-28 13:41:28 EDT (Thu, 28 May 2009)
@@ -8,33 +8,43 @@
[section:work_stealing Work-Stealing]
-The most important aspect of work-stealing is that it enables very fast enqueue and dequeue in the typical case, often requiring no synchronization at all. This virtually eliminates a large part of the overhead of QUWI, when working with child tasks. We still do need to allocate memory for the Task itself, and for the work-stealing queue, but like the improvements to the FIFO queue these data structures have been optimized for good GC performance. Parent tasks are fast; child tasks are much faster.
+The most important aspect of __work_stealing__ is that it enables fast enqueue and dequeue in the typical case, often requiring no synchronization at all. This virtually eliminates a large part of the overhead
+of QUWI, when working with child tasks. We still do need to allocate memory for the Task itself, and for the work-stealing queue, but like the improvements to the FIFO queue these data structures have been
+optimized for good GC performance. Parent tasks are fast; child tasks are much faster.
-Traditional thread pool do not scale because they use a single global queue protected by a global lock. The frequency at which __worker_threads__ aquire the global lock becomes a limiting factor for the throughput if:
+Traditional __thread_pools__ do not scale because they use a single global-queue protected by a global-lock. The frequency at which __worker_threads__ aquire the global-lock becomes
+a limiting factor for the throughput if:
* the __tasks__ become smaller
* more processors are added
-A work-stealing algorithm can be used to solve this problem. It uses a special kind of queue which has two ends, and allows lock-free pushes and pops from the ['private end] (accessed by the __worker_thread__ owning the queue), but requires synchronization from the ['public end] (accessed by the other __worker_threads__). Synchronization is necessary when the queue is sufficiently small that private and public operations could conflict.
-The pool contains one global queue (__bounded_channel__ or __unbounded_channel__) protected by a global lock and each __worker_thread__ has its own private worker queue. If work is enqueued by a __worker_thread__ the __action__ is stored in the worker queue. If the work is enqueued by a application thread it goes into the global queue. When __worker_threads__ are looking for work, they have following search order:
+A __work_stealing__ algorithm can be used to solve this problem. It uses a special kind of queue which has two ends, and allows lock-free pushes and pops from the ['private end]
+(accessed by the __worker_thread__ owning the queue), but requires synchronization from the ['public end] (accessed by the other __worker_threads__). Synchronization is necessary
+when the queue is sufficiently small that private and public operations could conflict.
-* look into the private worker queue - __actions__ can be dequeued without locks
+The pool contains one global-queue (__bounded_channel__ or __unbounded_channel__) protected by a global-lock and each __worker_thread__ has its own private local worker-queue.
+If work is enqueued by a __worker_thread__ the __action__ is stored in the worker queue. If the work is enqueued by a application thread it goes into the global queue. When
+__worker_threads__ are looking for work, they have following search order:
-* look in the global queue - locks are used for synchronization
+* look into the private worker-queue - __tasks__ can be dequeued without locks
-* check other worker queues ('stealing' __actions__ from private worker queues of other __worker_threads__) - requires locks
+* look in the global-queue - locks are used for synchronization
-For a lot of recursively queued __tasks__, the use of a worker queue per thread substantially reduces the synchronization necessary to complete the work. There are also fewer cache effects due to sharing of the global queue information.
+* check other worker-queues ('stealing' __tasks__ from private worker queues of other __worker_threads__) - requires locks
-Operations on the private worker queue are executed in LIFO order and operations on worker queues of other __worker_threads__ in FIFO order (steals).
-* There are chances that memory is still hot in the cache, if the __actions__ are pushed in LIFO order into the private worker queue.
+For a lot of recursively queued __tasks__ (so called __sub_tasks__), the use of a worker-queue per thread substantially reduces the synchronization necessary to complete the work. There are also fewer
+cache effects due to sharing of the global-queue information.
+
+Operations on the private worker queue are executed in LIFO order and operations on worker queues of other __worker_threads__ in FIFO order (steals).
-* If a __worker_thread__ steals work in FIFO order, increases the chances that a larger 'chunk' of work will be stolen (the need for other steals will be possibly reduced). Because the __tasks__ are stored in LIFO order, the oldest items are closer to the ['public end] of the queue (forming a tree). Stealing such an older __task__ also steals a (probably) larger subtree of __tasks__ unfolded if the stolen work item get executed.
+* There are chances that memory is still hot in the cache, if the __tasks__ are pushed in LIFO order into the private worker queue.
-Since a __sub_task__ is just a piece of a larger __task__, we donât need to worry about execution order. We just need to execute these things quickly. One well-known strategy for fast execution of unordered work items is __work_stealing__.
+* If a __worker_thread__ steals work in FIFO order, increases the chances that a larger 'chunk' of work will be stolen (the need for other steals will be possibly reduced).
+ Because the __sub_tasks__ are stored in LIFO order, the oldest items are closer to the ['public end] of the queue (forming a tree). Stealing such an older __task__ also steals
+ a (probably) larger subtree of __tasks__ unfolded if the stolen work item get executed. Since a __sub_task__ is just part of a larger __task__, we donât need to worry about execution order.
[endsect]
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