2
0
mirror of https://github.com/boostorg/fiber.git synced 2026-02-20 02:32:19 +00:00

remove task and tasklet

This commit is contained in:
Oliver Kowalke
2011-10-29 12:24:05 +02:00
parent af9f12d83c
commit 13f11221c3
224 changed files with 0 additions and 30899 deletions

View File

@@ -1,44 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKS_H
#define BOOST_TASKS_H
#include <boost/task/as_sub_task.hpp>
#include <boost/task/async.hpp>
#include <boost/task/bounded_fifo.hpp>
#include <boost/task/bounded_prio_queue.hpp>
#include <boost/task/bounded_smart_queue.hpp>
#include <boost/task/callable.hpp>
#include <boost/task/context.hpp>
#include <boost/task/exceptions.hpp>
#include <boost/task/fast_semaphore.hpp>
#include <boost/task/handle.hpp>
#include <boost/task/meta.hpp>
#include <boost/task/new_thread.hpp>
#include <boost/task/own_thread.hpp>
#include <boost/task/poolsize.hpp>
#include <boost/task/semaphore.hpp>
#include <boost/task/spin/auto_reset_event.hpp>
#include <boost/task/spin/barrier.hpp>
#include <boost/task/spin/bounded_channel.hpp>
#include <boost/task/spin/condition.hpp>
#include <boost/task/spin/count_down_event.hpp>
#include <boost/task/spin/future.hpp>
#include <boost/task/spin/manual_reset_event.hpp>
#include <boost/task/spin/mutex.hpp>
#include <boost/task/spin/unbounded_channel.hpp>
#include <boost/task/stacksize.hpp>
#include <boost/task/static_pool.hpp>
#include <boost/task/task.hpp>
#include <boost/task/unbounded_prio_queue.hpp>
#include <boost/task/unbounded_smart_queue.hpp>
#include <boost/task/unbounded_fifo.hpp>
#include <boost/task/utility.hpp>
#include <boost/task/watermark.hpp>
#endif // BOOST_TASKS_H

View File

@@ -1,51 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKS_AS_SUB_TASK_H
#define BOOST_TASKS_AS_SUB_TASK_H
#include <boost/bind.hpp>
#include <boost/config.hpp>
#include <boost/move/move.hpp>
#include <boost/task/callable.hpp>
#include <boost/task/context.hpp>
#include <boost/task/detail/worker.hpp>
#include <boost/task/handle.hpp>
#include <boost/task/new_thread.hpp>
#include <boost/task/spin/future.hpp>
#include <boost/task/task.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost {
namespace tasks {
struct as_sub_task
{
template< typename R >
handle< R > operator()( BOOST_RV_REF( task< R >) t)
{
detail::worker * w( detail::worker::tss_get() );
if ( w)
{
spin::promise< R > prom;
spin::shared_future< R > f( prom.get_future() );
context ctx;
handle< R > h( f, ctx);
w->put( callable( t, boost::move( prom), ctx) );
return h;
}
else
return new_thread()( t);
}
};
}}
#include <boost/config/abi_suffix.hpp>
#endif // BOOST_TASKS_AS_SUB_TASK_H

View File

@@ -1,128 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKS_ASYNC_H
#define BOOST_TASKS_ASYNC_H
#include <cstddef>
#include <boost/config.hpp>
#include <boost/move/move.hpp>
#include <boost/tasklet.hpp>
#include <boost/thread/future.hpp>
#include <boost/task/as_sub_task.hpp>
#include <boost/task/callable.hpp>
#include <boost/task/context.hpp>
#include <boost/task/handle.hpp>
#include <boost/task/new_thread.hpp>
#include <boost/task/own_thread.hpp>
#include <boost/task/spin/future.hpp>
#include <boost/task/static_pool.hpp>
#include <boost/task/task.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost {
namespace tasks {
template< typename R >
handle< R > async( task< R > t)
{ return async( boost::move( t) ); }
template< typename R >
handle< R > async( BOOST_RV_REF( task< R >) t)
{ return as_sub_task()( t); }
template< typename R >
handle< R > async( task< R > t, as_sub_task ast)
{ return async( boost::move( t), ast); }
template< typename R >
handle< R > async( BOOST_RV_REF( task< R >) t, as_sub_task ast)
{ return ast( t); }
template< typename R >
handle< R > async( task< R > t, own_thread ot)
{ return async( boost::move( t) ); }
template< typename R >
handle< R > async( BOOST_RV_REF( task< R >) t, own_thread ot)
{ return ot( t); }
template< typename R >
handle< R > async( task< R > t, new_thread nt)
{ return async( boost::move( t), nt); }
template< typename R >
handle< R > async( BOOST_RV_REF( task< R >) t, new_thread nt)
{ return nt( t); }
template< typename R, typename Queue, typename UMS >
handle< R > async( task< R > t, static_pool< Queue, UMS > & pool)
{ return async( boost::move(t), pool); }
template< typename R, typename Queue, typename UMS >
handle< R > async( BOOST_RV_REF( task< R >) t, static_pool< Queue, UMS > & pool)
{ return pool.submit( t); }
template< typename R, typename Attr, typename Queue, typename UMS >
handle< R > async( task< R > t, Attr attr, static_pool< Queue, UMS > & pool)
{ return async( boost::move(t), attr, pool); }
template< typename R, typename Attr, typename Queue, typename UMS >
handle< R > async( BOOST_RV_REF( task< R >) t, Attr attr, static_pool< Queue, UMS > & pool)
{ return pool.submit( t, attr); }
template< typename R, typename Strategy >
handle< R > async(
task< R > t,
tasklets::scheduler< Strategy > & sched,
std::size_t stacksize = tasklet::default_stacksize)
{ return async( boost::move( t), sched, stacksize); }
template< typename R, typename Strategy >
handle< R > async(
BOOST_RV_REF( task< R >) t,
tasklets::scheduler< Strategy > & sched,
std::size_t stacksize = tasklet::default_stacksize)
{
if ( this_task::runs_in_pool() )
{
spin::promise< R > prom;
spin::shared_future< R > f( prom.get_future() );
context ctx;
handle< R > h( f, ctx);
tasklet fib( callable( t, boost::move( prom), ctx), stacksize);
sched.submit_tasklet( boost::move( fib) );
return h;
}
else
{
promise< R > prom;
shared_future< R > f( prom.get_future() );
context ctx;
handle< R > h( f, ctx);
tasklet fib(
callable(
t,
// TODO: workaround because thread_move_t will be abigous for move
#ifdef BOOST_HAS_RVALUE_REFS
boost::move( prom),
#else
boost::detail::thread_move_t< promise< R > >( prom),
#endif
ctx), stacksize);
sched.submit_tasklet( boost::move( fib) );
return h;
}
}
}}
#include <boost/config/abi_suffix.hpp>
#endif // BOOST_TASKS_ASYNC_H

View File

@@ -1,205 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKS_BOUNDED_FIFO_H
#define BOOST_TASKS_BOUNDED_FIFO_H
#include <cstddef>
#include <boost/assert.hpp>
#include <boost/atomic.hpp>
#include <boost/bind.hpp>
#include <boost/foreach.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/shared_mutex.hpp>
#include <boost/task/callable.hpp>
#include <boost/task/detail/meta.hpp>
#include <boost/task/exceptions.hpp>
#include <boost/task/fast_semaphore.hpp>
#include <boost/task/watermark.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost {
namespace tasks {
class bounded_fifo
{
public:
typedef detail::has_no_attribute attribute_tag_type;
typedef callable value_type;
private:
struct node
{
typedef shared_ptr< node > sptr_t;
value_type va;
sptr_t next;
};
enum state
{
ACTIVE = 0,
DEACTIVE
};
atomic< state > state_;
atomic< std::size_t > count_;
node::sptr_t head_;
mutable mutex head_mtx_;
node::sptr_t tail_;
mutable mutex tail_mtx_;
condition not_full_cond_;
std::size_t hwm_;
std::size_t lwm_;
fast_semaphore & fsem_;
bool active_() const
{ return ACTIVE == state_.load(); }
void deactivate_()
{ state_.store( DEACTIVE); }
std::size_t size_() const
{ return count_.load(); }
bool empty_() const
{ return head_ == get_tail_(); }
bool full_() const
{ return size_() >= hwm_; }
node::sptr_t get_tail_() const
{
lock_guard< mutex > lk( tail_mtx_);
node::sptr_t tmp = tail_;
return tmp;
}
node::sptr_t pop_head_()
{
node::sptr_t old_head = head_;
head_ = old_head->next;
count_.fetch_sub( 1);
return old_head;
}
public:
bounded_fifo(
fast_semaphore & fsem,
high_watermark const& hwm,
low_watermark const& lwm) :
state_( ACTIVE),
count_( 0),
head_( new node),
head_mtx_(),
tail_( head_),
tail_mtx_(),
not_full_cond_(),
hwm_( hwm),
lwm_( lwm),
fsem_( fsem)
{}
std::size_t upper_bound() const
{ return hwm_; }
std::size_t lower_bound() const
{ return lwm_; }
bool active() const
{ return active_(); }
void deactivate()
{
unique_lock< mutex > lk( head_mtx_);
deactivate_();
not_full_cond_.notify_all();
}
bool empty() const
{
unique_lock< mutex > lk( head_mtx_);
return empty_();
}
void put( value_type const& va)
{
node::sptr_t new_node( new node);
{
unique_lock< mutex > lk( tail_mtx_);
if ( full_() )
{
while ( active_() && full_() )
not_full_cond_.wait( lk);
}
if ( ! active_() )
throw task_rejected("queue is not active");
tail_->va = va;
tail_->next = new_node;
tail_ = new_node;
count_.fetch_add( 1);
}
fsem_.post();
}
template< typename TimeDuration >
void put(
value_type const& va,
TimeDuration const& rel_time)
{
node::sptr_t new_node( new node);
{
unique_lock< mutex > lk( tail_mtx_);
if ( full_() )
{
while ( active_() && full_() )
if ( ! not_full_cond_.wait( lk, rel_time) )
throw task_rejected("timed out");
}
if ( ! active_() )
throw task_rejected("queue is not active");
tail_->va = va;
tail_->next = new_node;
tail_ = new_node;
count_.fetch_add( 1);
}
fsem_.post();
}
bool try_take( value_type & va)
{
unique_lock< mutex > lk( head_mtx_);
if ( empty_() )
return false;
va.swap( head_->va);
pop_head_();
bool valid = ! va.empty();
if ( valid && size_() <= lwm_)
{
if ( lwm_ == hwm_)
not_full_cond_.notify_one();
else
// more than one producer could be waiting
// in order to submit an task
not_full_cond_.notify_all();
}
return valid;
}
};
}}
#include <boost/config/abi_suffix.hpp>
#endif // BOOST_TASKS_BOUNDED_FIFO_H

View File

@@ -1,238 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKS_BOUNDED_PRIO_QUEUE_H
#define BOOST_TASKS_BOUNDED_PRIO_QUEUE_H
#include <algorithm>
#include <cstddef>
#include <functional>
#include <queue>
#include <boost/assert.hpp>
#include <boost/atomic.hpp>
#include <boost/bind.hpp>
#include <boost/foreach.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/shared_mutex.hpp>
#include <boost/task/callable.hpp>
#include <boost/task/detail/meta.hpp>
#include <boost/task/exceptions.hpp>
#include <boost/task/fast_semaphore.hpp>
#include <boost/task/watermark.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost {
namespace tasks {
template<
typename Attr,
typename Comp = std::less< Attr >
>
class bounded_prio_queue
{
public:
typedef detail::has_attribute attribute_tag_type;
typedef Attr attribute_type;
struct value_type
{
callable ca;
attribute_type attr;
value_type(
callable const& ca_,
attribute_type const& attr_) :
ca( ca_), attr( attr_)
{ BOOST_ASSERT( ! ca.empty() ); }
void swap( value_type & other)
{
ca.swap( other.ca);
std::swap( attr, other.attr);
}
};
private:
struct compare : public std::binary_function< value_type, value_type, bool >
{
bool operator()( value_type const& va1, value_type const& va2)
{ return Comp()( va1.attr, va2.attr); }
};
typedef std::priority_queue<
value_type,
std::deque< value_type >,
compare
> queue_type;
enum state
{
ACTIVE = 0,
DEACTIVE
};
atomic< state > state_;
queue_type queue_;
mutable shared_mutex mtx_;
condition not_full_cond_;
std::size_t hwm_;
std::size_t lwm_;
fast_semaphore & fsem_;
bool active_() const
{ return ACTIVE == state_.load(); }
void deactivate_()
{ state_.store( DEACTIVE); }
bool empty_() const
{ return queue_.empty(); }
bool full_() const
{ return size_() >= hwm_; }
std::size_t size_() const
{ return queue_.size(); }
void put_(
value_type const& va,
unique_lock< shared_mutex > & lk)
{
if ( full_() )
{
not_full_cond_.wait(
lk,
bind(
& bounded_prio_queue::producers_activate_,
this) );
}
if ( ! active_() )
throw task_rejected("queue is not active");
queue_.push( va);
fsem_.post();
}
template< typename TimeDuration >
void put_(
value_type const& va,
TimeDuration const& rel_time,
unique_lock< shared_mutex > & lk)
{
if ( full_() )
{
if ( ! not_full_cond_.timed_wait(
lk,
rel_time,
bind(
& bounded_prio_queue::producers_activate_,
this) ) )
throw task_rejected("timed out");
}
if ( ! active_() )
throw task_rejected("queue is not active");
queue_.push( va);
fsem_.post();
}
bool try_take_( callable & ca)
{
if ( empty_() )
return false;
callable tmp( queue_.top().ca);
queue_.pop();
ca.swap( tmp);
bool valid = ! ca.empty();
if ( valid && size_() <= lwm_)
{
if ( lwm_ == hwm_)
not_full_cond_.notify_one();
else
// more than one producer could be waiting
// in order to submit an task
not_full_cond_.notify_all();
}
return valid;
}
bool producers_activate_() const
{ return ! active_() || ! full_(); }
public:
bounded_prio_queue(
fast_semaphore & fsem,
high_watermark const& hwm,
low_watermark const& lwm) :
state_( ACTIVE),
queue_(),
mtx_(),
not_full_cond_(),
hwm_( hwm),
lwm_( lwm),
fsem_( fsem)
{
if ( lwm_ > hwm_ )
throw invalid_watermark();
}
bool active() const
{ return active_(); }
void deactivate()
{
unique_lock< shared_mutex > lk( mtx_);
deactivate_();
not_full_cond_.notify_all();
}
bool empty() const
{
shared_lock< shared_mutex > lk( mtx_);
return empty_();
}
std::size_t upper_bound() const
{
shared_lock< shared_mutex > lk( mtx_);
return hwm_;
}
std::size_t lower_bound() const
{
shared_lock< shared_mutex > lk( mtx_);
return lwm_;
}
void put( value_type const& va)
{
unique_lock< shared_mutex > lk( mtx_);
put_( va, lk);
}
template< typename TimeDuration >
void put(
value_type const& va,
TimeDuration const& rel_time)
{
unique_lock< shared_mutex > lk( mtx_);
put_( va, rel_time, lk);
}
bool try_take( callable & ca)
{
unique_lock< shared_mutex > lk( mtx_);
return try_take_( ca);
}
};
}}
#include <boost/config/abi_suffix.hpp>
#endif // BOOST_TASKS_BOUNDED_PRIO_QUEUE_H

View File

@@ -1,249 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKS_BOUNDED_SMART_QUEUE_H
#define BOOST_TASKS_BOUNDED_SMART_QUEUE_H
#include <algorithm>
#include <cstddef>
#include <boost/assert.hpp>
#include <boost/atomic.hpp>
#include <boost/bind.hpp>
#include <boost/foreach.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/shared_mutex.hpp>
#include <boost/task/callable.hpp>
#include <boost/task/detail/meta.hpp>
#include <boost/task/detail/smart.hpp>
#include <boost/task/exceptions.hpp>
#include <boost/task/fast_semaphore.hpp>
#include <boost/task/watermark.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost {
namespace tasks {
template<
typename Attr,
typename Comp,
typename Enq = detail::replace_oldest,
typename Deq = detail::take_oldest
>
class bounded_smart_queue
{
public:
typedef detail::has_attribute attribute_tag_type;
typedef Attr attribute_type;
struct value_type
{
callable ca;
attribute_type attr;
value_type(
callable const& ca_,
attribute_type const& attr_) :
ca( ca_), attr( attr_)
{ BOOST_ASSERT( ! ca.empty() ); }
void swap( value_type & other)
{
ca.swap( other.ca);
std::swap( attr, other.attr);
}
};
private:
typedef multi_index::multi_index_container<
value_type,
multi_index::indexed_by<
multi_index::ordered_non_unique<
multi_index::member<
value_type,
Attr,
& value_type::attr
>,
Comp
>
>
> queue_type;
typedef typename queue_type::template nth_index< 0 >::type queue_index;
enum state
{
ACTIVE = 0,
DEACTIVE
};
atomic< state > state_;
queue_type queue_;
queue_index & idx_;
mutable shared_mutex mtx_;
condition not_full_cond_;
Enq enq_op_;
Deq deq_op_;
std::size_t hwm_;
std::size_t lwm_;
fast_semaphore & fsem_;
bool active_() const
{ return ACTIVE == state_.load(); }
void deactivate_()
{ state_.store( DEACTIVE); }
bool empty_() const
{ return queue_.empty(); }
bool full_() const
{ return size_() >= hwm_; }
std::size_t size_() const
{ return queue_.size(); }
void put_(
value_type const& va,
unique_lock< shared_mutex > & lk)
{
if ( full_() )
{
not_full_cond_.wait(
lk,
bind(
& bounded_smart_queue::producers_activate_,
this) );
}
if ( ! active_() )
throw task_rejected("queue is not active");
enq_op_( idx_, va);
fsem_.post();
}
template< typename TimeDuration >
void put_(
value_type const& va,
TimeDuration const& rel_time,
unique_lock< shared_mutex > & lk)
{
if ( full_() )
{
if ( ! not_full_cond_.timed_wait(
lk,
rel_time,
bind(
& bounded_smart_queue::producers_activate_,
this) ) )
throw task_rejected("timed out");
}
if ( ! active_() )
throw task_rejected("queue is not active");
enq_op_( idx_, va);
fsem_.post();
}
bool try_take_( callable & ca)
{
if ( empty_() )
return false;
deq_op_( idx_, ca);
bool valid = ! ca.empty();
if ( valid && size_() <= lwm_)
{
if ( lwm_ == hwm_)
not_full_cond_.notify_one();
else
// more than one producer could be waiting
// in order to submit an task
not_full_cond_.notify_all();
}
return valid;
}
bool producers_activate_() const
{ return ! active_() || ! full_(); }
public:
bounded_smart_queue(
fast_semaphore & fsem,
high_watermark const& hwm,
low_watermark const& lwm) :
state_( ACTIVE),
queue_(),
idx_( queue_.get< 0 >() ),
mtx_(),
not_full_cond_(),
enq_op_(),
deq_op_(),
hwm_( hwm),
lwm_( lwm),
fsem_( fsem)
{
if ( lwm_ > hwm_ )
throw invalid_watermark();
}
bool active() const
{ return active_(); }
void deactivate()
{
unique_lock< shared_mutex > lk( mtx_);
deactivate_();
not_full_cond_.notify_all();
}
bool empty() const
{
shared_lock< shared_mutex > lk( mtx_);
return empty_();
}
std::size_t upper_bound() const
{
shared_lock< shared_mutex > lk( mtx_);
return hwm_;
}
std::size_t lower_bound() const
{
shared_lock< shared_mutex > lk( mtx_);
return lwm_;
}
void put( value_type const& va)
{
unique_lock< shared_mutex > lk( mtx_);
put_( va, lk);
}
template< typename TimeDuration >
void put(
value_type const& va,
TimeDuration const& rel_time)
{
unique_lock< shared_mutex > lk( mtx_);
put_( va, rel_time, lk);
}
bool try_take( callable & ca)
{
unique_lock< shared_mutex > lk( mtx_);
return try_take_( ca);
}
};
}}
#include <boost/config/abi_suffix.hpp>
#endif // BOOST_TASKS_BOUNDED_SMART_QUEUE_H

View File

@@ -1,165 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKS_CALLABLE_H
#define BOOST_TASKS_CALLABLE_H
#include <boost/config.hpp>
#include <boost/intrusive_ptr.hpp>
#include <boost/move/move.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>
#include <boost/task/context.hpp>
#include <boost/task/detail/config.hpp>
#include <boost/config/abi_prefix.hpp>
# if defined(BOOST_MSVC)
# pragma warning(push)
# pragma warning(disable:4251 4275)
# endif
namespace boost {
namespace tasks {
namespace detail {
struct BOOST_TASKS_DECL callable_base
{
atomic< unsigned int > use_count;
callable_base() :
use_count( 0)
{}
virtual ~callable_base() {}
virtual void run() = 0;
virtual void reset( shared_ptr< thread > const&) = 0;
inline friend void intrusive_ptr_add_ref( callable_base * p)
{ p->use_count.fetch_add( 1, memory_order_relaxed); }
inline friend void intrusive_ptr_release( callable_base * p)
{
if ( p->use_count.fetch_sub( 1, memory_order_release) == 1)
{
atomic_thread_fence( memory_order_acquire);
delete p;
}
}
};
template< typename Task, typename Promise >
class callable_object : public callable_base
{
private:
Task t_;
context ctx_;
public:
#ifdef BOOST_HAS_RVALUE_REFS
callable_object(
Task && t,
Promise && prom,
context const& ctx) :
t_( t), ctx_( ctx)
{ t_.set_promise( prom); }
#else
callable_object(
BOOST_RV_REF( Task) t,
boost::detail::thread_move_t< Promise > prom,
context const& ctx) :
t_( t), ctx_( ctx)
{ t_.set_promise( prom); }
#endif
callable_object(
BOOST_RV_REF( Task) t,
BOOST_RV_REF( Promise) prom,
context const& ctx) :
t_( t), ctx_( ctx)
{ t_.set_promise( prom); }
void run()
{ t_(); }
void reset( shared_ptr< thread > const& thrd)
{ ctx_.reset( thrd); }
};
}
class BOOST_TASKS_DECL callable
{
private:
intrusive_ptr< detail::callable_base > base_;
public:
callable();
#ifdef BOOST_HAS_RVALUE_REFS
template< typename Task, typename Promise >
callable(
Task && t,
Promise && prom,
context const& ctx) :
base_( new detail::callable_object< Task, Promise >( t, prom, ctx) )
{}
#else
template< typename Task, typename Promise >
callable(
BOOST_RV_REF( Task) t,
boost::detail::thread_move_t< Promise > prom,
context const& ctx) :
base_( new detail::callable_object< Task, Promise >( t, prom, ctx) )
{}
#endif
template< typename Task, typename Promise >
callable(
BOOST_RV_REF( Task) t,
BOOST_RV_REF( Promise) prom,
context const& ctx) :
base_( new detail::callable_object< Task, Promise >( t, prom, ctx) )
{}
void operator()();
bool empty() const;
void clear();
void reset( shared_ptr< thread > const&);
void swap( callable &);
};
class context_guard : private noncopyable
{
private:
callable & ca_;
public:
context_guard( callable & ca, shared_ptr< thread > const& thrd) :
ca_( ca)
{ ca_.reset( thrd); }
~context_guard()
{ ca_.clear(); }
};
}}
# if defined(BOOST_MSVC)
# pragma warning(pop)
# endif
#include <boost/config/abi_suffix.hpp>
#endif // BOOST_TASKS_CALLABLE_H

View File

@@ -1,94 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKS_CONTEXT_H
#define BOOST_TASKS_CONTEXT_H
#include <boost/atomic.hpp>
#include <boost/intrusive_ptr.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread_time.hpp>
#include <boost/utility.hpp>
#include <boost/task/detail/config.hpp>
#include <boost/config/abi_prefix.hpp>
# if defined(BOOST_MSVC)
# pragma warning(push)
# pragma warning(disable:4251 4275)
# endif
namespace boost {
namespace tasks {
namespace detail {
class BOOST_TASKS_DECL context_base : private noncopyable
{
private:
atomic< unsigned int > use_count_;
bool requested_;
mutex mtx_;
shared_ptr< thread > thrd_;
void reset_( shared_ptr< thread > const& thrd);
void interrupt_();
public:
context_base();
void reset( shared_ptr< thread > const& thrd);
void interrupt();
bool interruption_requested();
inline friend void intrusive_ptr_add_ref( context_base * p)
{ p->use_count_.fetch_add( 1, memory_order_relaxed); }
inline friend void intrusive_ptr_release( context_base * p)
{
if ( p->use_count_.fetch_sub( 1, memory_order_release) == 1)
{
atomic_thread_fence( memory_order_acquire);
delete p;
}
}
};
}
class BOOST_TASKS_DECL context
{
private:
intrusive_ptr< detail::context_base > base_;
public:
context();
void reset( shared_ptr< thread > const& thrd);
void interrupt();
bool interruption_requested();
void swap( context & other);
};
}}
# if defined(BOOST_MSVC)
# pragma warning(pop)
# endif
#include <boost/config/abi_suffix.hpp>
#endif // BOOST_TASKS_DETAIL_context_H

View File

@@ -1,37 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKS_DETAIL_BIND_PROCESSOR_H
#define BOOST_TASKS_DETAIL_BIND_PROCESSOR_H
#include <boost/task/detail/config.hpp>
# if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
# define BOOST_HAS_PROCESSOR_BINDINGS 1
# include <boost/task/detail/bind_processor_windows.hpp>
# elif defined(linux) || defined(__linux) || defined(__linux__)
# define BOOST_HAS_PROCESSOR_BINDINGS 1
# include <boost/task/detail/bind_processor_linux.hpp>
# elif defined(__IBMCPP__) || defined(_AIX)
# define BOOST_HAS_PROCESSOR_BINDINGS 1
# include <boost/task/detail/bind_processor_aix.hpp>
# elif defined(__hpux)
# define BOOST_HAS_PROCESSOR_BINDINGS 1
# include <boost/task/detail/bind_processor_hpux.hpp>
# elif defined(sun) || defined(__sun)
# define BOOST_HAS_PROCESSOR_BINDINGS 1
# include <boost/task/detail/bind_processor_solaris.hpp>
# elif defined(__FreeBSD__)
#include <sys/param.h>
# if (__FreeBSD_version >= 701000)
# define BOOST_HAS_PROCESSOR_BINDINGS 1
# include <boost/task/detail/bind_processor_freebsd.hpp>
# endif
# else
# undef BOOST_HAS_PROCESSOR_BINDINGS
# endif
#endif // BOOST_TASKS_DETAIL_BIND_PROCESSOR_H

View File

@@ -1,52 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKS_DETAIL_BIND_PROCESSOR_AIX_H
#define BOOST_TASKS_DETAIL_BIND_PROCESSOR_AIX_H
extern "C"
{
#include <sys/processor.h>
#include <sys/thread.h>
}
#include <boost/assert.hpp>
#include <boost/thread.hpp>
#include <boost/system/system_error.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost {
namespace this_thread {
inline
void bind_to_processor( unsigned int n)
{
BOOST_ASSERT( n >= 0);
BOOST_ASSERT( n < boost::thread::hardware_concurrency() );
if ( ::bindprocessor( BINDTHREAD, ::thread_self(), static_cast< cpu_t >( n) ) == -1)
throw boost::system::system_error(
boost::system::error_code(
errno,
boost::system::system_category() ) );
}
inline
void bind_to_any_processor()
{
if ( ::bindprocessor( BINDTHREAD, ::thread_self(), PROCESSOR_CLASS_ANY) == -1)
throw boost::system::system_error(
boost::system::error_code(
errno,
boost::system::system_category() ) );
}
}}
#include <boost/config/abi_suffix.hpp>
#endif // BOOST_TASKS_DETAIL_BIND_PROCESSOR_AIX_H

View File

@@ -1,63 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKS_DETAIL_BIND_PROCESSOR_FREEBSD_H
#define BOOST_TASKS_DETAIL_BIND_PROCESSOR_FREEBSD_H
extern "C"
{
#include <sys/param.h>
#include <sys/cpuset.h>
}
#include <boost/assert.hpp>
#include <boost/thread.hpp>
#include <boost/system/system_error.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost {
namespace this_thread {
inline
void bind_to_processor( unsigned int n)
{
BOOST_ASSERT( n >= 0);
BOOST_ASSERT( n < boost::thread::hardware_concurrency() );
cpuset_t cpuset;
CPU_ZERO( & cpuset);
CPU_SET( n, & cpuset);
if ( ::cpuset_setaffinity( CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof( cpuset), & cpuset) == -1)
throw boost::system::system_error(
boost::system::error_code(
errno,
boost::system::system_category() ) );
}
inline
void bind_to_any_processor()
{
cpuset_t cpuset;
CPU_ZERO( & cpuset);
unsigned int max( boost::thread::hardware_concurrency() );
for ( unsigned int i( 0); i < max; ++i)
CPU_SET( i, & cpuset);
if ( ::cpuset_setaffinity( CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof( cpuset), & cpuset) == -1)
throw boost::system::system_error(
boost::system::error_code(
errno,
boost::system::system_category() ) );
}
}}
#include <boost/config/abi_suffix.hpp>
#endif // BOOST_TASKS_DETAIL_BIND_PROCESSOR_FREEBSD_H

View File

@@ -1,65 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKS_DETAIL_BIND_PROCESSOR_HPUX_H
#define BOOST_TASKS_DETAIL_BIND_PROCESSOR_HPUX_H
extern "C"
{
#include <sys/pthread.h>
}
#include <boost/assert.hpp>
#include <boost/thread.hpp>
#include <boost/system/system_error.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost {
namespace this_thread {
inline
void bind_to_processor( unsigned int n)
{
BOOST_ASSERT( n >= 0);
BOOST_ASSERT( n < boost::thread::hardware_concurrency() );
::pthread_spu_t spu;
int errno_(
::pthread_processor_bind_np(
PTHREAD_BIND_FORCED_NP,
& spu,
static_cast< pthread_spu_t >( n),
PTHREAD_SELFTID_NP) );
if ( errno_ != 0)
throw boost::system::system_error(
boost::system::error_code(
errno_,
boost::system::system_category() ) );
}
inline
void bind_to_any_processor()
{
::pthread_spu_t spu;
int errno_(
::pthread_processor_bind_np(
PTHREAD_BIND_FORCED_NP,
& spu,
PTHREAD_SPUFLOAT_NP,
PTHREAD_SELFTID_NP) );
if ( errno_ != 0)
throw boost::system::system_error(
boost::system::error_code(
errno_,
boost::system::system_category() ) );
}
}}
#include <boost/config/abi_suffix.hpp>
#endif // BOOST_TASKS_DETAIL_BIND_PROCESSOR_HPUX_H

View File

@@ -1,66 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKS_DETAIL_BIND_PRCESSOR_LINUX_H
#define BOOST_TASKS_DETAIL_BIND_PRCESSOR_LINUX_H
extern "C"
{
#include <pthread.h>
#include <sched.h>
}
#include <boost/assert.hpp>
#include <boost/thread.hpp>
#include <boost/system/system_error.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost {
namespace this_thread {
inline
void bind_to_processor( unsigned int n)
{
BOOST_ASSERT( n >= 0);
BOOST_ASSERT( n < CPU_SETSIZE);
BOOST_ASSERT( n < boost::thread::hardware_concurrency() );
cpu_set_t cpuset;
CPU_ZERO( & cpuset);
CPU_SET( n, & cpuset);
int errno_( ::pthread_setaffinity_np( ::pthread_self(), sizeof( cpuset), & cpuset) );
if ( errno_ != 0)
throw boost::system::system_error(
boost::system::error_code(
errno_,
boost::system::system_category() ) );
}
inline
void bind_to_any_processor()
{
cpu_set_t cpuset;
CPU_ZERO( & cpuset);
unsigned int max( boost::thread::hardware_concurrency() );
for ( unsigned int i( 0); i < max; ++i)
CPU_SET( i, & cpuset);
int errno_( ::pthread_setaffinity_np( ::pthread_self(), sizeof( cpuset), & cpuset) );
if ( errno_ != 0)
throw boost::system::system_error(
boost::system::error_code(
errno_,
boost::system::system_category() ) );
}
}}
#include <boost/config/abi_suffix.hpp>
#endif // BOOST_TASKS_DETAIL_BIND_PRCESSOR_LINUX_H

View File

@@ -1,53 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKS_DETAIL_BIND_PROCESSOR_SOLARIS_H
#define BOOST_TASKS_DETAIL_BIND_PROCESSOR_SOLARIS_H
extern "C"
{
#include <sys/types.h>
#include <sys/processor.h>
#include <sys/procset.h>
}
#include <boost/assert.hpp>
#include <boost/thread.hpp>
#include <boost/system/system_error.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost {
namespace this_thread {
inline
void bind_to_processor( unsigned int n)
{
BOOST_ASSERT( n >= 0);
BOOST_ASSERT( n < boost::thread::hardware_concurrency() );
if ( ::processor_bind( P_LWPID, P_MYID, static_cast< processorid_t >( n), 0) == -1)
throw boost::system::system_error(
boost::system::error_code(
errno,
boost::system::system_category() ) );
}
inline
void bind_to_any_processor()
{
if ( ::processor_bind( P_LWPID, P_MYID, PBIND_NONE, 0) == -1)
throw boost::system::system_error(
boost::system::error_code(
errno,
boost::system::system_category() ) );
}
}}
#include <boost/config/abi_suffix.hpp>
#endif // BOOST_TASKS_DETAIL_BIND_PROCESSOR_SOLARIS_H

View File

@@ -1,55 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKS_DETAIL_BIND_PROCESSOR_WINDOWS_H
#define BOOST_TASKS_DETAIL_BIND_PROCESSOR_WINDOWS_H
extern "C"
{
#include <windows.h>
}
#include <boost/assert.hpp>
#include <boost/thread.hpp>
#include <boost/system/system_error.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost {
namespace this_thread {
inline
void bind_to_processor( unsigned int n)
{
BOOST_ASSERT( n >= 0);
BOOST_ASSERT( n < boost::thread::hardware_concurrency() );
if ( ::SetThreadAffinityMask( ::GetCurrentThread(), ( DWORD_PTR)1 << n) == 0)
throw boost::system::system_error(
boost::system::error_code(
::GetLastError(),
boost::system::system_category() ) );
}
inline
void bind_to_any_processor()
{
DWORD_PTR ptr( 1);
for ( unsigned int i( 0); i < boost::thread::hardware_concurrency(); ++i)
ptr = ptr << i;
if ( ::SetThreadAffinityMask( ::GetCurrentThread(), ptr) == 0)
throw boost::system::system_error(
boost::system::error_code(
::GetLastError(),
boost::system::system_category() ) );
}
}}
#include <boost/config/abi_suffix.hpp>
#endif // BOOST_TASKS_DETAIL_BIND_PROCESSOR_WINDOWS_H

View File

@@ -1,80 +0,0 @@
// Copyright Oliver Kowalke 2009.
// 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)
// this file is based on config.hpp of boost.thread
#ifndef BOOST_TASKS_DETAIL_CONFIG_H
#define BOOST_TASKS_DETAIL_CONFIG_H
#include <boost/config.hpp>
#include <boost/detail/workaround.hpp>
# if BOOST_WORKAROUND(__BORLANDC__, < 0x600)
# pragma warn -8008 // Condition always true/false
# pragma warn -8080 // Identifier declared but never used
# pragma warn -8057 // Parameter never used
# pragma warn -8066 // Unreachable code
# endif
# if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_TASKS_DYN_LINK)
# undef BOOST_TASKS_USE_LIB
# define BOOST_TASKS_USE_DLL
# endif
# if defined(BOOST_TASKS_BUILD_DLL) //Build dll
# elif defined(BOOST_TASKS_BUILD_LIB) //Build lib
# elif defined(BOOST_TASKS_USE_DLL) //Use dll
# elif defined(BOOST_TASKS_USE_LIB) //Use lib
# else //Use default
# if defined(BOOST_TASKS_PLATFORM_WIN32)
# if defined(BOOST_MSVC) || defined(BOOST_INTEL_WIN)
//For compilers supporting auto-tss cleanup
//with Boost.Threads lib, use Boost.Threads lib
# define BOOST_TASKS_USE_LIB
# else
//For compilers not yet supporting auto-tss cleanup
//with Boost.Threads lib, use Boost.Threads dll
# define BOOST_TASKS_USE_DLL
# endif
# else
# define BOOST_TASKS_USE_LIB
# endif
# endif
# if defined(BOOST_HAS_DECLSPEC)
# if defined(BOOST_TASKS_BUILD_DLL) //Build dll
# define BOOST_TASKS_DECL __declspec(dllexport)
# elif defined(BOOST_TASKS_USE_DLL) //Use dll
# define BOOST_TASKS_DECL __declspec(dllimport)
# else
# define BOOST_TASKS_DECL
# endif
# else
# define BOOST_TASKS_DECL
# endif
// Automatically link to the correct build variant where possible.
# if ! defined(BOOST_ALL_NO_LIB) && ! defined(BOOST_TASKS_NO_LIB) && ! defined(BOOST_TASKS_BUILD_DLL) && ! defined(BOOST_TASKS_BUILD_LIB)
// Tell the autolink to link dynamically, this will get undef'ed by auto_link.hpp
# if defined(BOOST_TASKS_USE_DLL)
# define BOOST_DYN_LINK
# endif
// Set the name of our library, this will get undef'ed by auto_link.hpp
# if defined(BOOST_TASKS_LIB_NAME)
# define BOOST_LIB_NAME BOOST_TASKS_LIB_NAME
# else
# define BOOST_LIB_NAME boost_task
# endif
// If we're importing code from a dll, then tell auto_link.hpp about it
// And include the header that does the work
#include <boost/config/auto_link.hpp>
# endif // auto-linking disabled
#endif // BOOST_TASKS_DETAIL_CONFIG_H

View File

@@ -1,82 +0,0 @@
// (C) Copyright 2008-9 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKS_DETAIL_FUTURE_TRAITSHPP
#define BOOST_TASKS_DETAIL_FUTURE_TRAITSHPP
#include <algorithm>
#include <list>
#include <stdexcept>
#include <vector>
#include <boost/config.hpp>
#include <boost/move/move.hpp>
#include <boost/mpl/if.hpp>
#include <boost/next_prior.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/type_traits/is_fundamental.hpp>
namespace boost {
namespace tasks {
namespace detail {
template<typename T>
struct future_traits
{
typedef boost::scoped_ptr<T> storage_type;
#ifdef BOOST_HAS_RVALUE_REFS
typedef T const& source_reference_type;
struct dummy;
typedef typename boost::mpl::if_<boost::is_fundamental<T>,dummy&,T&&>::type rvalue_source_type;
typedef typename boost::mpl::if_<boost::is_fundamental<T>,T,T&&>::type move_dest_type;
#else
typedef T& source_reference_type;
typedef typename boost::mpl::if_<boost::is_convertible<T&, BOOST_RV_REF( T) >, BOOST_RV_REF( T),T const&>::type rvalue_source_type;
typedef typename boost::mpl::if_<boost::is_convertible<T&,BOOST_RV_REF( T) >,BOOST_RV_REF( T),T>::type move_dest_type;
#endif
static void init(storage_type& storage,source_reference_type t)
{ storage.reset(new T(t)); }
static void init(storage_type& storage,rvalue_source_type t)
{ storage.reset(new T(static_cast<rvalue_source_type>(t))); }
static void cleanup(storage_type& storage)
{ storage.reset(); }
};
template<typename T>
struct future_traits<T&>
{
typedef T* storage_type;
typedef T& source_reference_type;
struct rvalue_source_type {};
typedef T& move_dest_type;
static void init(storage_type& storage,T& t)
{ storage=&t; }
static void cleanup(storage_type& storage)
{ storage=0; }
};
template<>
struct future_traits<void>
{
typedef bool storage_type;
typedef void move_dest_type;
static void init(storage_type& storage)
{ storage=true; }
static void cleanup(storage_type& storage)
{ storage=false; }
};
}}}
#endif // BOOST_TASKS_DETAIL_FUTURE_TRAITS_H

View File

@@ -1,27 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKS_DETAIL_INFO_H
#define BOOST_TASKS_DETAIL_INFO_H
#include <boost/config/abi_prefix.hpp>
namespace boost {
namespace tasks {
namespace detail {
struct has_attribute
{};
struct has_no_attribute
{};
}}}
#include <boost/config/abi_suffix.hpp>
#endif // BOOST_TASKS_DETAIL_INFO_H

View File

@@ -1,369 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKS_DETAIL_POOL_BASE_H
#define BOOST_TASKS_DETAIL_POOL_BASE_H
#include <cstddef>
#include <boost/assert.hpp>
#include <boost/atomic.hpp>
#include <boost/bind.hpp>
#include <boost/config.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>
#include <boost/thread/detail/move.hpp>
#include <boost/thread/future.hpp>
#include <boost/task/callable.hpp>
#include <boost/task/context.hpp>
#include <boost/task/detail/bind_processor.hpp>
#include <boost/task/detail/worker_group.hpp>
#include <boost/task/detail/worker.hpp>
#include <boost/task/exceptions.hpp>
#include <boost/task/fast_semaphore.hpp>
#include <boost/task/handle.hpp>
#include <boost/task/poolsize.hpp>
#include <boost/task/spin/future.hpp>
#include <boost/task/stacksize.hpp>
#include <boost/task/task.hpp>
#include <boost/task/utility.hpp>
#include <boost/task/watermark.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost {
namespace tasks {
namespace detail {
template<
typename Queue,
typename UMS
>
class pool_base
{
private:
friend class worker;
template< typename T, typename Z >
friend class worker_object;
template< typename T, typename Z >
friend void intrusive_ptr_add_ref( pool_base< T, Z > * p);
template< typename T, typename Z >
friend void intrusive_ptr_release( pool_base< T, Z > * p);
typedef Queue queue_type;
typedef typename queue_type::value_type value_type;
typedef UMS ums_type;
enum state
{
ACTIVE = 0,
DEACTIVE
};
fast_semaphore fsem_;
atomic< unsigned int > use_count_;
worker_group wg_;
shared_mutex mtx_wg_;
atomic< state > state_;
queue_type queue_;
atomic< bool > shtdwn_;
atomic< bool > shtdwn_now_;
void worker_entry_()
{
shared_lock< shared_mutex > lk( mtx_wg_);
typename detail::worker_group::iterator i( wg_.find( this_thread::get_id() ) );
lk.unlock();
BOOST_ASSERT( i != wg_.end() );
worker w( * i);
w.run();
}
void create_worker_(
poolsize const& psize,
stacksize const& stack_size)
{
wg_.insert(
worker(
* this,
psize,
stack_size,
boost::bind(
& pool_base::worker_entry_,
this) ) );
}
# if defined(BOOST_HAS_PROCESSOR_BINDINGS)
void worker_entry_( std::size_t n)
{
this_thread::bind_to_processor( n);
worker_entry_();
}
void create_worker_(
poolsize const& psize,
stacksize const& stack_size,
std::size_t n)
{
wg_.insert(
worker(
* this,
psize,
stack_size,
boost::bind(
& pool_base::worker_entry_,
this,
n) ) );
}
# endif
std::size_t size_() const
{ return wg_.size(); }
bool deactivated_() const
{ return DEACTIVE == state_.load(); }
bool deactivate_()
{ return ACTIVE == state_.exchange( DEACTIVE); }
public:
explicit pool_base(
poolsize const& psize,
stacksize const& stack_size) :
fsem_( 0),
use_count_( 0),
wg_(),
mtx_wg_(),
state_( ACTIVE),
queue_( fsem_),
shtdwn_( false),
shtdwn_now_( false)
{
lock_guard< shared_mutex > lk( mtx_wg_);
for ( std::size_t i( 0); i < psize; ++i)
create_worker_( psize, stack_size);
}
explicit pool_base(
poolsize const& psize,
high_watermark const& hwm,
low_watermark const& lwm,
stacksize const& stack_size) :
fsem_( 0),
use_count_( 0),
wg_(),
mtx_wg_(),
state_( ACTIVE),
queue_( fsem_, hwm, lwm),
shtdwn_( false),
shtdwn_now_( false)
{
lock_guard< shared_mutex > lk( mtx_wg_);
for ( std::size_t i( 0); i < psize; ++i)
create_worker_( psize, stack_size);
}
# if defined(BOOST_HAS_PROCESSOR_BINDINGS)
explicit pool_base( stacksize const& stack_size) :
fsem_( 0),
use_count_( 0),
wg_(),
mtx_wg_(),
state_( ACTIVE),
queue_( fsem_),
shtdwn_( false),
shtdwn_now_( false)
{
poolsize psize( thread::hardware_concurrency() );
BOOST_ASSERT( psize > 0);
lock_guard< shared_mutex > lk( mtx_wg_);
for ( std::size_t i( 0); i < psize; ++i)
create_worker_( psize, stack_size, i);
}
explicit pool_base(
high_watermark const& hwm,
low_watermark const& lwm,
stacksize const& stack_size) :
fsem_( 0),
use_count_( 0),
wg_(),
mtx_wg_(),
state_( ACTIVE),
queue_( fsem_, hwm, lwm),
shtdwn_( false),
shtdwn_now_( false)
{
poolsize psize( thread::hardware_concurrency() );
BOOST_ASSERT( psize > 0);
lock_guard< shared_mutex > lk( mtx_wg_);
for ( std::size_t i( 0); i < psize; ++i)
create_worker_( psize, stack_size, i);
}
# endif
~pool_base()
{ shutdown(); }
void interrupt_all_worker()
{
if ( deactivated_() ) return;
shared_lock< shared_mutex > lk( mtx_wg_);
wg_.interrupt_all();
}
void shutdown()
{
if ( deactivated_() || ! deactivate_() ) return;
queue_.deactivate();
fsem_.deactivate();
shared_lock< shared_mutex > lk( mtx_wg_);
shtdwn_.store( true);
wg_.join_all();
}
const void shutdown_now()
{
if ( deactivated_() || ! deactivate_() ) return;
queue_.deactivate();
fsem_.deactivate();
shared_lock< shared_mutex > lk( mtx_wg_);
shtdwn_now_.store( true);
wg_.interrupt_all();
wg_.join_all();
}
std::size_t size()
{
shared_lock< shared_mutex > lk( mtx_wg_);
return size_();
}
bool closed()
{ return deactivated_(); }
std::size_t upper_bound()
{ return queue_.upper_bound(); }
void upper_bound( high_watermark const& hwm)
{ queue_.upper_bound( hwm); }
std::size_t lower_bound()
{ return queue_.lower_bound(); }
void lower_bound( low_watermark const lwm)
{ queue_.lower_bound( lwm); }
template< typename R >
handle< R > submit( BOOST_RV_REF( task< R >) t)
{
if ( deactivated_() )
throw task_rejected("pool is closed");
if ( this_task::runs_in_pool() )
{
spin::promise< R > prom;
spin::shared_future< R > f( prom.get_future() );
context ctx;
handle< R > h( f, ctx);
queue_.put( callable( t, boost::move( prom), ctx) );
return h;
}
else
{
promise< R > prom;
shared_future< R > f( prom.get_future() );
context ctx;
handle< R > h( f, ctx);
queue_.put(
callable(
t,
// TODO: workaround because thread_move_t will be abigous for move
#ifdef BOOST_HAS_RVALUE_REFS
boost::move( prom),
#else
boost::detail::thread_move_t< promise< R > >( prom),
#endif
ctx) );
return h;
}
}
template< typename R, typename Attr >
handle< R > submit( BOOST_RV_REF( task< R >) t, Attr const& attr)
{
if ( deactivated_() )
throw task_rejected("pool is closed");
if ( this_task::runs_in_pool() )
{
spin::promise< R > prom;
spin::shared_future< R > f( prom.get_future() );
context ctx;
handle< R > h( f, ctx);
queue_.put(
value_type(
callable( t, boost::move( prom), ctx),
attr) );
return h;
}
else
{
promise< R > prom;
shared_future< R > f( prom.get_future() );
// TODO: if boost.thread uses boost.move
// use boost::move()
context ctx;
handle< R > h( f, ctx);
queue_.put(
value_type(
callable(
t,
// TODO: workaround because thread_move_t will be abigous for move
#ifdef BOOST_HAS_RVALUE_REFS
boost::move( prom),
#else
boost::detail::thread_move_t< promise< R > >( prom),
#endif
ctx),
attr) );
return h;
}
}
};
template<
typename Queue,
typename UMS
>
void intrusive_ptr_add_ref( pool_base< Queue, UMS > * p)
{ p->use_count_.fetch_add( 1, memory_order_relaxed); }
template<
typename Queue,
typename UMS
>
void intrusive_ptr_release( pool_base< Queue, UMS > * p)
{
if ( p->use_count_.fetch_sub( 1, memory_order_release) == 1)
{
atomic_thread_fence( memory_order_acquire);
delete p;
}
}
}}}
#include <boost/config/abi_suffix.hpp>
#endif // BOOST_TASKS_DETAIL_POOL_BASE_H

View File

@@ -1,67 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_DETAIL_SMART_H
#define BOOST_DETAIL_SMART_H
#include <boost/task/callable.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost {
namespace tasks {
namespace detail {
struct replace_oldest
{
template<
typename PrioIndex,
typename Value
>
void operator()( PrioIndex & idx, Value const& va)
{
typedef typename PrioIndex::iterator iterator;
iterator i( idx.find( va.attr) );
if ( i == idx.end() )
idx.insert( va);
else
idx.replace( i, va);
}
};
struct take_oldest
{
class swapper
{
private:
callable & ca_;
public:
swapper( callable & ca) :
ca_( ca)
{}
template< typename Value >
void operator()( Value & va)
{ ca_.swap( va.ca); }
};
template< typename PrioIndex >
void operator()( PrioIndex & idx, callable & ca)
{
typedef typename PrioIndex::iterator iterator;
iterator i( idx.begin() );
BOOST_ASSERT( i != idx.end() );
idx.modify( i, swapper( ca) );
idx.erase( i);
}
};
}}}
#include <boost/config/abi_suffix.hpp>
#endif // BOOST_TASKS_DETAIL_SMART_H

View File

@@ -1,279 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKS_DETAIL_WORKER_H
#define BOOST_TASKS_DETAIL_WORKER_H
#include <cstddef>
#include <utility>
#include <boost/assert.hpp>
#include <boost/tasklet.hpp>
#include <boost/function.hpp>
#include <boost/random.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>
#include <boost/utility.hpp>
#include <boost/task/callable.hpp>
#include <boost/task/detail/config.hpp>
#include <boost/task/detail/wsq.hpp>
#include <boost/task/poolsize.hpp>
#include <boost/task/stacksize.hpp>
#include <boost/config/abi_prefix.hpp>
# if defined(BOOST_MSVC)
# pragma warning(push)
# pragma warning(disable:4251 4275)
# endif
namespace boost {
namespace tasks {
namespace detail {
struct worker_base
{
virtual ~worker_base() {}
virtual const thread::id get_id() const = 0;
virtual void join() const = 0;
virtual void interrupt() const = 0;
virtual void put( callable const&) = 0;
virtual bool try_steal( callable &) = 0;
virtual void run() = 0;
virtual void yield() = 0;
};
template<
typename Pool,
typename Worker
>
class worker_object : public worker_base,
private noncopyable
{
private:
class random_idx
{
private:
rand48 rng_;
uniform_int<> six_;
variate_generator< rand48 &, uniform_int<> > die_;
public:
random_idx( std::size_t size) :
rng_(),
six_( 0, size - 1),
die_( rng_, six_)
{}
std::size_t operator()()
{ return die_(); }
};
typedef shared_ptr< thread > thread_t;
Pool & pool_;
thread_t thrd_;
tasklets::scheduler<
typename Pool::ums_type > * sched_;// TODO: make not as pointer if WIN32 Fiber API is replaced by assembler
wsq wsq_;
bool shtdwn_;
std::size_t stack_size_;
random_idx rnd_idx_;
void execute_( callable & ca)
{
BOOST_ASSERT( ! ca.empty() );
{
context_guard lk( ca, thrd_);
ca();
}
ca.clear();
BOOST_ASSERT( ca.empty() );
}
bool try_take_global_callable_( callable & ca)
{ return pool_.queue_.try_take( ca); }
bool try_take_local_callable_( callable & ca)
{ return wsq_.try_take( ca); }
bool try_steal_other_callable_( callable & ca)
{
std::size_t idx( rnd_idx_() );
for ( std::size_t j( 0); j < pool_.wg_.size(); ++j)
{
Worker other( pool_.wg_[idx]);
if ( this_thread::get_id() == other.get_id() ) continue;
if ( ++idx >= pool_.wg_.size() ) idx = 0;
if ( other.try_steal( ca) )
return true;
}
return false;
}
void run_()
{
while ( ! shutdown_() )
{
callable ca;
if ( try_take_local_callable_( ca) ||
try_steal_other_callable_( ca) ||
try_take_global_callable_( ca) )
{
execute_( ca);
if ( 0 < sched_->ready() ) return;
}
else
{
if ( 0 < sched_->ready() ) return;
pool_.fsem_.wait();
}
}
}
bool shutdown_()
{
if ( shutdown__() && pool_.queue_.empty() && 0 == sched_->ready() )
return true;
else if ( shutdown_now__() )
return true;
return false;
}
bool shutdown__()
{
if ( ! shtdwn_)
shtdwn_ = pool_.shtdwn_;
return shtdwn_;
}
bool shutdown_now__()
{ return pool_.shtdwn_now_; }
public:
worker_object(
Pool & pool,
poolsize const& psize,
stacksize const& stack_size,
function< void() > const& fn) :
pool_( pool),
thrd_( new thread( fn) ),
sched_(),
wsq_( pool_.fsem_),
shtdwn_( false),
stack_size_( stack_size),
rnd_idx_( psize)
{ BOOST_ASSERT( ! fn.empty() ); }
~worker_object()
{ delete sched_; }
const thread::id get_id() const
{ return thrd_->get_id(); }
void join() const
{ thrd_->join(); }
void
interrupt() const
{ thrd_->interrupt(); }
void put( callable const& ca)
{
BOOST_ASSERT( ! ca.empty() );
wsq_.put( ca);
}
bool try_steal( callable & ca)
{ return wsq_.try_steal( ca); }
void run()
{
// TODO: remove if WIN32 Fiber API is replaced by assembler
sched_ = new tasklets::scheduler< typename Pool::ums_type >();
BOOST_ASSERT( get_id() == this_thread::get_id() );
sched_->submit_tasklet(
tasklets::make_tasklet(
bind(
& worker_object::run_,
this),
stack_size_) );
while ( ! shutdown_() )
sched_->run();
}
void yield()
{
sched_->submit_tasklet(
tasklets::make_tasklet(
bind(
& worker_object::run_,
this),
stack_size_) );
this_tasklet::yield();
}
};
class BOOST_TASKS_DECL worker
{
private:
static thread_specific_ptr< worker > tss_;
shared_ptr< worker_base > impl_;
public:
template< typename Pool >
worker(
Pool & pool,
poolsize const& psize,
stacksize const& stack_size,
function< void() > const& fn) :
impl_(
new worker_object< Pool, worker >(
pool,
psize,
stack_size,
fn) )
{}
const thread::id get_id() const;
void join() const;
void interrupt() const;
void put( callable const&);
bool try_steal( callable &);
void run();
void yield();
static worker * tss_get();
};
}}}
# if defined(BOOST_MSVC)
# pragma warning(pop)
# endif
#include <boost/config/abi_suffix.hpp>
#endif // BOOST_TASKS_DETAIL_WORKER_H

View File

@@ -1,101 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKS_DETAIL_WORKER_GROUP_H
#define BOOST_TASKS_DETAIL_WORKER_GROUP_H
#include <cstddef>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/mem_fun.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <boost/thread.hpp>
#include <boost/task/detail/config.hpp>
#include <boost/task/detail/worker.hpp>
#include <boost/config/abi_prefix.hpp>
# if defined(BOOST_MSVC)
# pragma warning(push)
# pragma warning(disable:4251 4275)
# endif
namespace boost {
namespace tasks {
namespace detail {
class BOOST_TASKS_DECL worker_group
{
private:
struct id_idx_tag {};
struct rnd_idx_tag {};
typedef multi_index::multi_index_container<
worker,
multi_index::indexed_by<
multi_index::ordered_unique<
multi_index::tag< id_idx_tag >,
multi_index::const_mem_fun<
worker,
const thread::id,
& worker::get_id
>
>,
multi_index::random_access< multi_index::tag< rnd_idx_tag > >
>
> container;
typedef container::index< id_idx_tag >::type id_idx;
typedef container::index< rnd_idx_tag >::type rnd_idx;
container cont_;
id_idx & id_idx_;
rnd_idx & rnd_idx_;
public:
typedef id_idx::iterator iterator;
typedef id_idx::const_iterator const_iterator;
worker_group();
~worker_group();
std::size_t size() const;
bool empty() const;
const worker operator[]( std::size_t pos) const;
const iterator begin();
const const_iterator begin() const;
const iterator end();
const const_iterator end() const;
const const_iterator find( thread::id const& id) const;
void insert( worker const& w);
iterator erase( iterator const& i);
void join_all();
void interrupt_all();
};
}}}
# if defined(BOOST_MSVC)
# pragma warning(pop)
# endif
#include <boost/config/abi_suffix.hpp>
#endif // BOOST_TASKS_DETAIL_WORKER_GROUP_H

View File

@@ -1,65 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKS_DETAIL_WSQ_H
#define BOOST_TASKS_DETAIL_WSQ_H
#include <boost/atomic.hpp>
#include <boost/shared_array.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/utility.hpp>
#include <boost/task/callable.hpp>
#include <boost/task/detail/config.hpp>
#include <boost/task/fast_semaphore.hpp>
#include <boost/config/abi_prefix.hpp>
# if defined(BOOST_MSVC)
# pragma warning(push)
# pragma warning(disable:4251 4275)
# endif
namespace boost {
namespace tasks {
namespace detail {
class BOOST_TASKS_DECL wsq : private noncopyable
{
private:
const int initial_size_;
shared_array< callable > array_;
int capacity_;
int mask_;
atomic< unsigned int > head_idx_;
atomic< unsigned int > tail_idx_;
recursive_mutex mtx_;
fast_semaphore & fsem_;
public:
wsq( fast_semaphore & fsem);
bool empty() const;
std::size_t size() const;
void put( callable const&);
bool try_take( callable &);
bool try_steal( callable &);
};
}}}
# if defined(BOOST_MSVC)
# pragma warning(pop)
# endif
#include <boost/config/abi_suffix.hpp>
#endif // BOOST_TASKS_DETAIL_WSQ_H

View File

@@ -1,105 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKS_EXCEPTIONS_H
#define BOOST_TASKS_EXCEPTIONS_H
#include <stdexcept>
#include <string>
#include <boost/config/abi_prefix.hpp>
namespace boost {
namespace tasks {
class invalid_poolsize : public std::invalid_argument
{
public:
invalid_poolsize() :
std::invalid_argument("core poolsize must be greater than zero")
{}
};
class invalid_stacksize : public std::invalid_argument
{
public:
invalid_stacksize() :
std::invalid_argument("stacksize must be greater than zero")
{}
};
class invalid_watermark : public std::invalid_argument
{
public:
invalid_watermark() :
std::invalid_argument("invalid watermark")
{}
};
class task_uninitialized : public std::logic_error
{
public:
task_uninitialized() :
std::logic_error("task uninitialized")
{}
};
class task_already_executed : public std::logic_error
{
public:
task_already_executed() :
std::logic_error("task already executed")
{}
};
class task_moved : public std::logic_error
{
public:
task_moved() :
std::logic_error("task moved")
{}
};
class broken_task : public std::logic_error
{
public:
broken_task() :
std::logic_error("broken task")
{}
};
struct task_interrupted
{};
class task_rejected : public std::runtime_error
{
public:
task_rejected( std::string const& msg) :
std::runtime_error( msg)
{}
};
class pool_moved : public std::logic_error
{
public:
pool_moved() :
std::logic_error("pool moved")
{}
};
class lock_error : public std::logic_error
{
public:
lock_error() :
std::logic_error("lock invalid")
{}
};
}}
#include <boost/config/abi_suffix.hpp>
#endif // BOOST_TASKS_EXCEPTIONS_H

View File

@@ -1,48 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASK_FAST_SEMAPHORE_H
#define BOOST_TASK_FAST_SEMAPHORE_H
#include <boost/task/detail/config.hpp>
#include <boost/atomic.hpp>
#include <boost/utility.hpp>
#include <boost/task/semaphore.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost {
namespace tasks {
class BOOST_TASKS_DECL fast_semaphore : private boost::noncopyable
{
private:
unsigned int spin_count_;
atomic< int > sem_count_;
atomic< bool > sem_active_;
semaphore sem_;
public:
fast_semaphore( int, unsigned int = 0);
~fast_semaphore();
void post( int = 1);
void wait();
bool try_wait();
void deactivate();
};
}}
#include <boost/config/abi_suffix.hpp>
#endif // BOOST_TASK_FAST_SEMAPHORE_H

View File

@@ -1,285 +0,0 @@
// Copyright Oliver Kowalke 2009.
// 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)
//
// parts are based on boost.future by Anthony Williams
#ifndef BOOST_TASKS_HANDLE_H
#define BOOST_TASKS_HANDLE_H
#include <boost/atomic.hpp>
#include <boost/intrusive_ptr.hpp>
#include <boost/thread.hpp>
#include <boost/thread/thread_time.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/task/context.hpp>
#include <boost/task/spin/future.hpp>
#include <boost/task/exceptions.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost {
namespace tasks {
namespace detail {
template< typename R >
struct handle_base
{
template< typename X >
friend void intrusive_ptr_add_ref( handle_base< X > *);
template< typename X >
friend void intrusive_ptr_release( handle_base< X > *);
typedef intrusive_ptr< handle_base > ptr;
atomic< unsigned int > use_count;
virtual ~handle_base() {}
virtual void interrupt() = 0;
virtual void interrupt_and_wait() = 0;
virtual bool interrupt_and_wait_until( system_time const& abs_time) = 0;
virtual bool interruption_requested() = 0;
virtual R get() = 0;
virtual bool is_ready() const = 0;
virtual bool has_value() const = 0;
virtual bool has_exception() const = 0;
virtual void wait() const = 0;
virtual bool wait_until( system_time const& abs_time) const = 0;
};
template< typename R >
void intrusive_ptr_add_ref( handle_base< R > * p)
{ p->use_count.fetch_add( 1, memory_order_relaxed); }
template< typename R >
void intrusive_ptr_release( handle_base< R > * p)
{
if ( p->use_count.fetch_sub( 1, memory_order_release) == 1)
{
atomic_thread_fence( memory_order_acquire);
delete p;
}
}
template< typename R, typename F >
class handle_object : public handle_base< R >
{
private:
F fut_;
context ctx_;
public:
handle_object() :
fut_(),
ctx_()
{}
handle_object(
F const& fut,
context const& ctx) :
fut_( fut),
ctx_( ctx)
{}
void interrupt()
{ ctx_.interrupt(); }
void interrupt_and_wait()
{
interrupt();
wait();
}
bool interrupt_and_wait_until( system_time const& abs_time)
{
interrupt();
return wait_until( abs_time);
}
bool interruption_requested()
{ return ctx_.interruption_requested(); }
R get()
{
try
{ return fut_.get(); }
catch ( future_uninitialized const&)
{ throw task_uninitialized(); }
catch ( broken_promise const&)
{ throw broken_task(); }
catch ( promise_already_satisfied const&)
{ throw task_already_executed(); }
}
bool is_ready() const
{ return fut_.is_ready(); }
bool has_value() const
{ return fut_.has_value(); }
bool has_exception() const
{ return fut_.has_exception(); }
void wait() const
{
try
{ fut_.wait(); }
catch ( future_uninitialized const&)
{ throw task_uninitialized(); }
catch ( broken_promise const&)
{ throw broken_task(); }
catch ( thread_interrupted const&)
{ throw task_interrupted(); }
}
bool wait_until( system_time const& abs_time) const
{
try
{ return fut_.timed_wait_until( abs_time); }
catch ( future_uninitialized const&)
{ throw task_uninitialized(); }
catch ( broken_promise const&)
{ throw broken_task(); }
catch ( thread_interrupted const&)
{ throw task_interrupted(); }
}
};
}
template< typename T >
struct is_handle_type;
template< typename R >
class handle
{
private:
intrusive_ptr< detail::handle_base< R > > base_;
public:
handle() :
base_( new detail::handle_object< R, spin::shared_future< R > >() )
{}
template< typename F >
handle(
F const& fut,
context const& ctx) :
base_( new detail::handle_object< R, F >( fut, ctx) )
{}
void interrupt()
{ base_->interrupt(); }
void interrupt_and_wait()
{ base_->interrupt_and_wait(); }
bool interrupt_and_wait_until( system_time const& abs_time)
{ return base_->interrupt_and_wait_until( abs_time); }
template< typename TimeDuration >
bool interrupt_and_wait_for( TimeDuration const& rel_time)
{ return interrupt_and_wait_until( get_system_time() + rel_time); }
bool interruption_requested()
{ return base_->interruption_requested(); }
R get()
{ return base_->get(); }
bool is_ready() const
{ return base_->is_ready(); }
bool has_value() const
{ return base_->has_value(); }
bool has_exception() const
{ return base_->has_exception(); }
void wait() const
{ base_->wait(); }
bool wait_until( system_time const& abs_time) const
{ return base_->wait_until( abs_time); }
template< typename TimeDuration >
bool wait_for( TimeDuration const& rel_time) const
{ return wait_until( get_system_time() + rel_time); }
void swap( handle< R > & other)
{ base_.swap( other.base_); }
};
template< typename T >
struct is_handle_type
{ BOOST_STATIC_CONSTANT( bool, value = false); };
template< typename T >
struct is_handle_type< handle< T > >
{
BOOST_STATIC_CONSTANT( bool, value = true);
};
template< typename Iterator >
typename disable_if< is_handle_type< Iterator >, void >::type waitfor_all(
Iterator begin, Iterator end)
{
for ( Iterator i = begin; i != end; ++i)
i->wait();
}
template< typename R1, typename R2 >
void waitfor_all( handle< R1 > & h1, handle< R2 > & h2)
{
h1.wait();
h2.wait();
}
template< typename R1, typename R2, typename R3 >
void waitfor_all( handle< R1 > & h1, handle< R2 > & h2, handle< R3 > & h3)
{
h1.wait();
h2.wait();
h3.wait();
}
template< typename R1, typename R2, typename R3, typename R4 >
void waitfor_all(
handle< R1 > & h1, handle< R2 > & h2, handle< R3 > & h3, handle< R4 > & h4)
{
h1.wait();
h2.wait();
h3.wait();
h4.wait();
}
template< typename R1, typename R2, typename R3, typename R4, typename R5 >
void waitfor_all(
handle< R1 > & h1, handle< R2 > & h2, handle< R3 > & h3, handle< R4 > & h4,
handle< R5 > & h5)
{
h1.wait();
h2.wait();
h3.wait();
h4.wait();
h5.wait();
}
}}
#include <boost/config/abi_suffix.hpp>
#endif // BOOST_TASKS_HANDLE_H

View File

@@ -1,40 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKS_META_H
#define BOOST_TASKS_META_H
#include <boost/mpl/bool.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/task/detail/meta.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost {
namespace tasks {
template< typename Pool >
struct has_attribute : public mpl::bool_<
is_same<
detail::has_attribute,
typename Pool::queue_type::attribute_tag_type
>::value
>
{};
template< typename Pool >
struct attribute_type
{
typedef typename Pool::queue_type::attribute_type type;
};
}}
#include <boost/config/abi_suffix.hpp>
#endif // BOOST_TASKS_META_H

View File

@@ -1,94 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKS_NEW_THREAD_H
#define BOOST_TASKS_NEW_THREAD_H
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <boost/move/move.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>
#include <boost/thread/future.hpp>
#include <boost/task/callable.hpp>
#include <boost/task/context.hpp>
#include <boost/task/handle.hpp>
#include <boost/task/spin/future.hpp>
#include <boost/task/task.hpp>
#include <boost/task/utility.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost {
namespace tasks {
namespace detail {
struct joiner
{
void operator()( thread * thrd)
{
try
{
BOOST_ASSERT( thrd);
BOOST_ASSERT( thrd->joinable() );
thrd->join();
}
catch (...)
{}
delete thrd;
}
};
}
struct new_thread
{
template< typename R >
handle< R > operator()( BOOST_RV_REF( task< R >) t)
{
if ( this_task::runs_in_pool() )
{
spin::promise< R > prom;
spin::shared_future< R > f( prom.get_future() );
context ctx1, ctx2;
handle< R > h( f, ctx1);
callable ca( t, boost::move( prom), ctx2);
shared_ptr< thread > thrd(
new thread( ca),
detail::joiner() );
ctx1.reset( thrd);
return h;
}
else
{
promise< R > prom;
shared_future< R > f( prom.get_future() );
context ctx1, ctx2;
handle< R > h( f, ctx1);
callable ca(
t,
// TODO: workaround because thread_move_t will be abigous for move
#ifdef BOOST_HAS_RVALUE_REFS
boost::move( prom),
#else
boost::detail::thread_move_t< promise< R > >( prom),
#endif
ctx2);
shared_ptr< thread > thrd(
new thread( ca),
detail::joiner() );
ctx1.reset( thrd);
return h;
}
}
};
}}
#include <boost/config/abi_suffix.hpp>
#endif // BOOST_TASKS_NEW_THREAD_H

View File

@@ -1,66 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKS_OWN_THREAD_H
#define BOOST_TASKS_OWN_THREAD_H
#include <boost/config.hpp>
#include <boost/move/move.hpp>
#include <boost/thread/future.hpp>
#include <boost/task/callable.hpp>
#include <boost/task/context.hpp>
#include <boost/task/handle.hpp>
#include <boost/task/spin/future.hpp>
#include <boost/task/task.hpp>
#include <boost/task/utility.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost {
namespace tasks {
struct own_thread
{
template< typename R >
handle< R > operator()( BOOST_RV_REF( task< R >) t)
{
if ( this_task::runs_in_pool() )
{
spin::promise< R > prom;
spin::shared_future< R > f( prom.get_future() );
context ctx;
handle< R > h( f, ctx);
callable ca( t, boost::move( prom), ctx);
ca();
return h;
}
else
{
promise< R > prom;
shared_future< R > f( prom.get_future() );
context ctx;
handle< R > h( f, ctx);
callable ca(
t,
// TODO: workaround because thread_move_t will be abigous for move
#ifdef BOOST_HAS_RVALUE_REFS
boost::move( prom),
#else
boost::detail::thread_move_t< promise< R > >( prom),
#endif
ctx);
ca();
return h;
}
}
};
}}
#include <boost/config/abi_suffix.hpp>
#endif // BOOST_TASKS_OWN_THREAD_H

View File

@@ -1,43 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKS_POOLSIZE_H
#define BOOST_TASKS_POOLSIZE_H
#include <cstddef>
#include <boost/task/detail/config.hpp>
#include <boost/config/abi_prefix.hpp>
# if defined(BOOST_MSVC)
# pragma warning(push)
# pragma warning(disable:4251 4275)
# endif
namespace boost {
namespace tasks {
class BOOST_TASKS_DECL poolsize
{
private:
std::size_t value_;
public:
explicit poolsize( std::size_t value);
operator std::size_t () const;
};
}}
# if defined(BOOST_MSVC)
# pragma warning(pop)
# endif
#include <boost/config/abi_suffix.hpp>
#endif // BOOST_TASKS_POOLSIZE_H

View File

@@ -1,64 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASK_SEMAPHORE_H
#define BOOST_TASK_SEMAPHORE_H
#include <boost/task/detail/config.hpp>
extern "C"
{
# if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__CYGWIN__)
#include <Windows.h>
# else
#include <sys/sem.h>
# endif
}
#include <boost/utility.hpp>
#include <boost/task/detail/config.hpp>
#include <boost/config/abi_prefix.hpp>
# if defined(BOOST_MSVC)
# pragma warning(push)
# pragma warning(disable:4251 4275)
# endif
namespace boost {
namespace tasks {
class BOOST_TASKS_DECL semaphore : private boost::noncopyable
{
private:
# if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__CYGWIN__)
HANDLE handle_;
# else
int handle_;
# endif
public:
semaphore( int);
~semaphore();
void post( int = 1);
void wait();
bool try_wait();
};
}}
# if defined(BOOST_MSVC)
# pragma warning(pop)
# endif
#include <boost/config/abi_suffix.hpp>
#endif // BOOST_TASK_SEMAPHORE_H

View File

@@ -1,49 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKS_SPIN_AUTO_RESET_EVENT_H
#define BOOST_TASKS_SPIN_AUTO_RESET_EVENT_H
#include <boost/atomic.hpp>
#include <boost/thread/thread_time.hpp>
#include <boost/utility.hpp>
#include <boost/task/detail/config.hpp>
namespace boost {
namespace tasks {
namespace spin {
class BOOST_TASKS_DECL auto_reset_event : private noncopyable
{
private:
enum state
{
SET = 0,
RESET
};
atomic< state > state_;
public:
explicit auto_reset_event( bool = false);
void set();
void wait();
bool try_wait();
bool timed_wait( system_time const&);
template< typename TimeDuration >
bool timed_wait( TimeDuration const& rel_time)
{ return timed_wait( get_system_time() + rel_time); }
};
}}}
#endif // BOOST_TASKS_SPIN_AUTO_RESET_EVENT_H

View File

@@ -1,39 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKS_SPIN_BARRIER_H
#define BOOST_TASKS_SPIN_BARRIER_H
#include <cstddef>
#include <boost/utility.hpp>
#include <boost/task/detail/config.hpp>
#include <boost/task/spin/condition.hpp>
#include <boost/task/spin/mutex.hpp>
namespace boost {
namespace tasks {
namespace spin {
class BOOST_TASKS_DECL barrier : private noncopyable
{
private:
std::size_t initial_;
std::size_t current_;
bool cycle_;
mutex mtx_;
condition cond_;
public:
barrier( std::size_t);
bool wait();
};
}}}
#endif // BOOST_TASKS_SPIN_BARRIER_H

View File

@@ -1,398 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKS_SPIN_BOUNDED_CHANNEL_H
#define BOOST_TASKS_SPIN_BOUNDED_CHANNEL_H
#include <cstddef>
#include <stdexcept>
#include <boost/atomic.hpp>
#include <boost/intrusive_ptr.hpp>
#include <boost/optional.hpp>
#include <boost/thread/thread_time.hpp>
#include <boost/utility.hpp>
#include <boost/task/exceptions.hpp>
#include <boost/task/spin/condition.hpp>
#include <boost/task/spin/mutex.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost {
namespace tasks {
namespace spin {
namespace detail {
template< typename T >
struct bounded_channel_base_node
{
typedef intrusive_ptr< bounded_channel_base_node > ptr;
atomic< std::size_t > use_count;
T va;
ptr next;
bounded_channel_base_node() :
use_count( 0),
va(),
next()
{}
};
template< typename T >
void intrusive_ptr_add_ref( bounded_channel_base_node< T > * p)
{ p->use_count.fetch_add( 1, memory_order_relaxed); }
template< typename T >
void intrusive_ptr_release( bounded_channel_base_node< T > * p)
{
if ( p->use_count.fetch_sub( 1, memory_order_release) == 1)
{
atomic_thread_fence( memory_order_acquire);
delete p;
}
}
template< typename T >
class bounded_channel_base : private noncopyable
{
public:
typedef optional< T > value_type;
private:
typedef bounded_channel_base_node< value_type > node_type;
template< typename X >
friend void intrusive_ptr_add_ref( bounded_channel_base< X > * p);
template< typename X >
friend void intrusive_ptr_release( bounded_channel_base< X > * p);
enum state
{
ACTIVE = 0,
DEACTIVE
};
atomic< state > state_;
atomic< std::size_t > count_;
typename node_type::ptr head_;
mutable mutex head_mtx_;
typename node_type::ptr tail_;
mutable mutex tail_mtx_;
condition not_empty_cond_;
condition not_full_cond_;
unsigned int hwm_;
unsigned int lwm_;
atomic< std::size_t > use_count_;
bool active_() const
{ return ACTIVE == state_.load(); }
void deactivate_()
{ state_.store( DEACTIVE); }
std::size_t size_() const
{ return count_.load(); }
bool empty_() const
{ return head_ == get_tail_(); }
bool full_() const
{ return size_() >= hwm_; }
typename node_type::ptr get_tail_() const
{
mutex::scoped_lock lk( tail_mtx_);
typename node_type::ptr tmp = tail_;
return tmp;
}
typename node_type::ptr pop_head_()
{
typename node_type::ptr old_head = head_;
head_ = old_head->next;
count_.fetch_sub( 1);
return old_head;
}
public:
bounded_channel_base(
std::size_t hwm,
std::size_t lwm) :
state_( ACTIVE),
count_( 0),
head_( new node_type() ),
head_mtx_(),
tail_( head_),
tail_mtx_(),
not_empty_cond_(),
not_full_cond_(),
hwm_( hwm),
lwm_( lwm),
use_count_( 0)
{
if ( hwm_ < lwm_)
throw invalid_watermark();
}
bounded_channel_base( std::size_t wm) :
state_( ACTIVE),
count_( 0),
head_( new node_type() ),
head_mtx_(),
tail_( head_),
tail_mtx_(),
not_empty_cond_(),
not_full_cond_(),
hwm_( wm),
lwm_( wm),
use_count_( 0)
{}
std::size_t upper_bound() const
{ return hwm_; }
std::size_t lower_bound() const
{ return lwm_; }
bool active() const
{ return active_(); }
void deactivate()
{
mutex::scoped_lock head_lk( head_mtx_);
mutex::scoped_lock tail_lk( tail_mtx_);
not_empty_cond_.notify_all();
not_full_cond_.notify_all();
deactivate_();
}
bool empty() const
{
mutex::scoped_lock lk( head_mtx_);
return empty_();
}
void put( T const& t)
{
typename node_type::ptr new_node( new node_type() );
{
mutex::scoped_lock lk( tail_mtx_);
if ( full_() )
{
while ( active_() && full_() )
not_full_cond_.wait( lk);
}
if ( ! active_() )
throw std::runtime_error("queue is not active");
tail_->va = t;
tail_->next = new_node;
tail_ = new_node;
count_.fetch_add( 1);
}
not_empty_cond_.notify_one();
}
bool put( T const& t, system_time const& abs_time)
{
typename node_type::ptr new_node( new node_type() );
{
mutex::scoped_lock lk( tail_mtx_);
if ( full_() )
{
while ( active_() && full_() )
if ( ! not_full_cond_.timed_wait( lk, abs_time) );
return false;
}
if ( ! active_() )
throw std::runtime_error("queue is not active");
tail_->va = t;
tail_->next = new_node;
tail_ = new_node;
count_.fetch_add( 1);
}
not_empty_cond_.notify_one();
return true;
}
bool take( value_type & va)
{
mutex::scoped_lock lk( head_mtx_);
bool empty = empty_();
if ( ! active_() && empty)
return false;
if ( empty)
{
try
{
while ( active_() && empty_() )
not_empty_cond_.wait( lk);
}
catch ( task_interrupted const&)
{ return false; }
}
if ( ! active_() && empty_() )
return false;
swap( va, head_->va);
pop_head_();
if ( size_() <= lwm_)
{
if ( lwm_ == hwm_)
not_full_cond_.notify_one();
else
// more than one producer could be waiting
// for submiting an action object
not_full_cond_.notify_all();
}
return va;
}
bool take( value_type & va, system_time const& abs_time)
{
mutex::scoped_lock lk( head_mtx_);
bool empty = empty_();
if ( ! active_() && empty)
return false;
if ( empty)
{
try
{
while ( active_() && empty_() )
if ( ! not_empty_cond_.timed_wait( lk, abs_time) )
return false;
}
catch ( task_interrupted const&)
{ return false; }
}
if ( ! active_() && empty_() )
return false;
swap( va, head_->va);
pop_head_();
if ( size_() <= lwm_)
{
if ( lwm_ == hwm_)
not_full_cond_.notify_one();
else
// more than one producer could be waiting
// for submiting an action object
not_full_cond_.notify_all();
}
return va;
}
bool try_take( value_type & va)
{
mutex::scoped_lock lk( head_mtx_);
if ( empty_() )
return false;
swap( va, head_->va);
pop_head_();
bool valid = va;
if ( valid && size_() <= lwm_)
{
if ( lwm_ == hwm_)
not_full_cond_.notify_one();
else
// more than one producer could be waiting
// in order to submit an task
not_full_cond_.notify_all();
}
return valid;
}
};
template< typename T >
void intrusive_ptr_add_ref( bounded_channel_base< T > * p)
{ p->use_count_.fetch_add( 1, memory_order_relaxed); }
template< typename T >
void intrusive_ptr_release( bounded_channel_base< T > * p)
{
if ( p->use_count_.fetch_sub( 1, memory_order_release) == 1)
{
atomic_thread_fence( memory_order_acquire);
delete p;
}
}
}
template< typename T >
class bounded_channel
{
private:
typedef typename detail::bounded_channel_base< T >::value_type value_type;
intrusive_ptr< detail::bounded_channel_base< T > > base_;
public:
bounded_channel(
std::size_t hwm,
std::size_t lwm) :
base_( new detail::bounded_channel_base< T >( hwm, lwm) )
{}
bounded_channel( std::size_t wm) :
base_( new detail::bounded_channel_base< T >( wm) )
{}
void upper_bound( std::size_t hwm)
{ base_->upper_bound( hwm); }
std::size_t upper_bound() const
{ return base_->upper_bound(); }
void lower_bound( std::size_t lwm)
{ base_->lower_bound( lwm); }
std::size_t lower_bound() const
{ return base_->lower_bound(); }
bool active() const
{ return base_->active(); }
void deactivate()
{ base_->deactivate(); }
bool empty() const
{ return base_->empty(); }
void put( T const& t)
{ base_->put( t); }
bool put( T const& t, system_time const& abs_time)
{ return base_->put( t, abs_time); }
template< typename TimeDuration >
bool put( T const& t, TimeDuration const& rel_time)
{ return base_->put( t, get_system_time() + rel_time); }
bool take( value_type & va)
{ return base_->take( va);}
bool take( value_type & va, system_time const& abs_time)
{ return base_->take( va, abs_time);}
template< typename TimeDuration >
bool take( value_type & va, TimeDuration const& rel_time)
{ return base_->take( va, get_system_time() + rel_time);}
bool try_take( value_type & va)
{ return base_->try_take( va); }
};
}}}
#include <boost/config/abi_suffix.hpp>
#endif // BOOST_TASKS_SPIN_BOUNDED_CHANNEL_H

View File

@@ -1,293 +0,0 @@
// Copyright Oliver Kowalke 2009.
// 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)
//
// based on boost::interprocess::sync::interprocess_condition
#ifndef BOOST_TASKS_SPIN_CONDITION_H
#define BOOST_TASKS_SPIN_CONDITION_H
#include <cstddef>
#include <boost/assert.hpp>
#include <boost/atomic.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/thread_time.hpp>
#include <boost/utility.hpp>
#include <boost/task/detail/config.hpp>
#include <boost/task/exceptions.hpp>
#include <boost/task/spin/mutex.hpp>
#include <boost/task/utility.hpp>
namespace boost {
namespace tasks {
namespace spin {
class BOOST_TASKS_DECL condition : private noncopyable
{
private:
enum command
{
SLEEPING = 0,
NOTIFY_ONE,
NOTIFY_ALL
};
atomic< command > cmd_;
atomic< std::size_t > waiters_;
mutex enter_mtx_;
mutex check_mtx_;
void notify_( command);
public:
condition();
void notify_one();
void notify_all();
void wait( unique_lock< mutex > & lk)
{
if ( ! lk)
throw lock_error();
wait( * lk.mutex() );
}
template< typename Pred >
void wait( unique_lock< mutex > & lk, Pred pred)
{
if ( ! lk)
throw lock_error();
while ( ! pred() )
wait( * lk.mutex() );
}
bool timed_wait( unique_lock< mutex > & lk, system_time const& abs_time)
{
if ( abs_time.is_infinity() )
{
wait( lk);
return true;
}
if ( ! lk)
throw lock_error();
return timed_wait( * lk.mutex(), abs_time);
}
template< typename Pred >
bool timed_wait( unique_lock< mutex > & lk, system_time const& abs_time, Pred pred)
{
if ( abs_time.is_infinity() )
{
wait( lk, pred);
return true;
}
if ( ! lk)
throw lock_error();
while ( ! pred() )
if ( ! timed_wait( * lk.mutex(), abs_time) )
return pred();
return true;
}
template< typename TimeDuration >
bool timed_wait( unique_lock< mutex > & lk, TimeDuration const& rel_time)
{ return timed_wait( lk, get_system_time() + rel_time); }
template<
typename TimeDuration,
typename Pred
>
bool timed_wait( unique_lock< mutex > & lk, TimeDuration const& rel_time, Pred pred)
{ return timed_wait( lk, get_system_time() + rel_time, pred); }
template< typename LockType >
void wait( LockType & lt)
{
{
mutex::scoped_lock lk( enter_mtx_);
BOOST_ASSERT( lk);
waiters_.fetch_add( 1);
lt.unlock();
}
bool unlock_enter_mtx = false;
for (;;)
{
while ( SLEEPING == cmd_.load() )
{
this_thread::interruption_point();
if ( this_task::runs_in_pool() )
this_task::yield();
else
this_thread::yield();
this_thread::interruption_point();
}
mutex::scoped_lock lk( check_mtx_);
BOOST_ASSERT( lk);
command expected = NOTIFY_ONE;
cmd_.compare_exchange_strong( expected, SLEEPING);
if ( SLEEPING == expected)
continue;
else if ( NOTIFY_ONE == expected)
{
unlock_enter_mtx = true;
waiters_.fetch_sub( 1);
break;
}
else
{
unlock_enter_mtx = 1 == waiters_.fetch_sub( 1);
if ( unlock_enter_mtx)
{
expected = NOTIFY_ALL;
cmd_.compare_exchange_strong( expected, SLEEPING);
}
break;
}
}
if ( unlock_enter_mtx)
enter_mtx_.unlock();
lt.lock();
}
template<
typename LockType,
typename Pred
>
void wait( LockType & lt, Pred pred)
{
while ( ! pred() )
wait( lt);
}
template< typename LockType >
bool timed_wait( LockType & lt, system_time const& abs_time)
{
if ( abs_time.is_infinity() )
{
wait( lt);
return true;
}
if ( get_system_time() >= abs_time) return false;
{
mutex::scoped_lock lk( enter_mtx_, abs_time);
BOOST_ASSERT( lk);
waiters_.fetch_add( 1);
lt.unlock();
}
bool timed_out = false, unlock_enter_mtx = false;
for (;;)
{
while ( SLEEPING == cmd_.load() )
{
this_thread::interruption_point();
if ( this_task::runs_in_pool() )
this_task::yield();
else
this_thread::yield();
this_thread::interruption_point();
if ( get_system_time() >= abs_time)
{
timed_out = enter_mtx_.try_lock();
if ( ! timed_out)
continue;
break;
}
}
if ( timed_out)
{
waiters_.fetch_sub( 1);
unlock_enter_mtx = true;
break;
}
else
{
mutex::scoped_lock lk( check_mtx_);
BOOST_ASSERT( lk);
command expected = NOTIFY_ONE;
cmd_.compare_exchange_strong( expected, SLEEPING);
if ( SLEEPING == expected)
continue;
else if ( NOTIFY_ONE == expected)
{
unlock_enter_mtx = true;
waiters_.fetch_sub( 1);
break;
}
else
{
unlock_enter_mtx = 1 == waiters_.fetch_sub( 1);
if ( unlock_enter_mtx)
{
expected = NOTIFY_ALL;
cmd_.compare_exchange_strong( expected, SLEEPING);
}
break;
}
}
}
if ( unlock_enter_mtx)
enter_mtx_.unlock();
lt.lock();
return ! timed_out;
}
template<
typename LockType,
typename Pred
>
bool timed_wait( LockType & lt, system_time const& abs_time, Pred pred)
{
if ( abs_time.is_infinity() )
{
wait( lt, pred);
return true;
}
while ( ! pred() )
if ( ! wait( lt, abs_time) )
return pred();
return true;
}
template<
typename LockType,
typename TimeDuration
>
bool timed_wait( LockType & lt, TimeDuration const& rel_time)
{ return timed_wait( lt, get_system_time() + rel_time); }
template<
typename LockType,
typename TimeDuration,
typename Pred
>
bool timed_wait( LockType & lt, TimeDuration const& rel_time, Pred pred)
{ return timed_wait( lt, get_system_time() + rel_time, pred); }
};
}}}
#endif // BOOST_TASKS_SPIN_CONDITION_H

View File

@@ -1,50 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKS_SPIN_COUNT_DOWN_EVENT_H
#define BOOST_TASKS_SPIN_COUNT_DOWN_EVENT_H
#include <cstddef>
#include <boost/atomic.hpp>
#include <boost/thread/thread_time.hpp>
#include <boost/utility.hpp>
#include <boost/task/detail/config.hpp>
namespace boost {
namespace tasks {
namespace spin {
class BOOST_TASKS_DECL count_down_event : private noncopyable
{
private:
std::size_t initial_;
atomic< std::size_t > current_;
public:
explicit count_down_event( std::size_t);
std::size_t initial() const;
std::size_t current() const;
bool is_set() const;
void set();
void wait();
bool timed_wait( system_time const&);
template< typename TimeDuration >
bool timed_wait( TimeDuration const& rel_time)
{ return timed_wait( get_system_time() + rel_time); }
};
}}}
#endif // BOOST_TASKS_SPIN_COUNT_DOWN_EVENT_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,56 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKS_SPIN_MANUAL_RESET_EVENT_H
#define BOOST_TASKS_SPIN_MANUAL_RESET_EVENT_H
#include <cstddef>
#include <boost/atomic.hpp>
#include <boost/thread/thread_time.hpp>
#include <boost/utility.hpp>
#include <boost/task/detail/config.hpp>
#include <boost/task/spin/mutex.hpp>
namespace boost {
namespace tasks {
namespace spin {
class BOOST_TASKS_DECL manual_reset_event : private noncopyable
{
private:
enum state
{
SET = 0,
RESET
};
atomic< state > state_;
atomic< std::size_t > waiters_;
mutex enter_mtx_;
public:
explicit manual_reset_event( bool = false);
void set();
void reset();
void wait();
bool try_wait();
bool timed_wait( system_time const&);
template< typename TimeDuration >
bool timed_wait( TimeDuration const& rel_time)
{ return timed_wait( get_system_time() + rel_time); }
};
}}}
#endif // BOOST_TASKS_SPIN_MANUAL_RESET_EVENT_H

View File

@@ -1,56 +0,0 @@
// Copyright Oliver Kowalke 2009.
// 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)
//
// based on boost::interprocess::sync::interprocess_spin::mutex
#ifndef BOOST_TASKS_SPIN_MUTEX_H
#define BOOST_TASKS_SPIN_MUTEX_H
#include <boost/atomic.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/thread_time.hpp>
#include <boost/utility.hpp>
#include <boost/task/detail/config.hpp>
namespace boost {
namespace tasks {
namespace spin {
class BOOST_TASKS_DECL mutex : private noncopyable
{
private:
enum state
{
LOCKED = 0,
UNLOCKED
};
atomic< state > state_;
public:
typedef unique_lock< mutex > scoped_lock;
mutex();
void lock();
bool try_lock();
bool timed_lock( system_time const& abs_time);
template< typename TimeDuration >
bool timed_lock( TimeDuration const& rel_time)
{ return timed_lock( get_system_time() + rel_time); }
void unlock();
};
typedef mutex try_mutex;
}}}
#endif // BOOST_TASKS_SPIN_MUTEX_H

View File

@@ -1,273 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKS_SPIN_UNBOUNDED_CHANNEL_H
#define BOOST_TASKS_SPIN_UNBOUNDED_CHANNEL_H
#include <cstddef>
#include <stdexcept>
#include <boost/atomic.hpp>
#include <boost/config.hpp>
#include <boost/intrusive_ptr.hpp>
#include <boost/optional.hpp>
#include <boost/thread/thread_time.hpp>
#include <boost/utility.hpp>
#include <boost/task/exceptions.hpp>
#include <boost/task/spin/condition.hpp>
#include <boost/task/spin/mutex.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost {
namespace tasks {
namespace spin {
namespace detail {
template< typename T >
struct unbounded_channel_base_node
{
typedef intrusive_ptr< unbounded_channel_base_node > ptr;
atomic< std::size_t > use_count;
T va;
ptr next;
unbounded_channel_base_node() :
use_count( 0),
va(),
next()
{}
};
template< typename T >
void intrusive_ptr_add_ref( unbounded_channel_base_node< T > * p)
{ p->use_count.fetch_add( 1, memory_order_relaxed); }
template< typename T >
void intrusive_ptr_release( unbounded_channel_base_node< T > * p)
{
if ( p->use_count.fetch_sub( 1, memory_order_release) == 1)
{
atomic_thread_fence( memory_order_acquire);
delete p;
}
}
template< typename T >
class unbounded_channel_base : private noncopyable
{
public:
typedef optional< T > value_type;
private:
typedef unbounded_channel_base_node< value_type > node_type;
template< typename X >
friend void intrusive_ptr_add_ref( unbounded_channel_base< X > * p);
template< typename X >
friend void intrusive_ptr_release( unbounded_channel_base< X > * p);
enum state
{
ACTIVE = 0,
DEACTIVE
};
atomic< state > state_;
typename node_type::ptr head_;
mutable mutex head_mtx_;
typename node_type::ptr tail_;
mutable mutex tail_mtx_;
condition not_empty_cond_;
atomic< std::size_t > use_count_;
bool active_() const
{ return ACTIVE == state_.load(); }
void deactivate_()
{ state_.store( DEACTIVE); }
bool empty_() const
{ return head_ == get_tail_(); }
typename node_type::ptr get_tail_() const
{
mutex::scoped_lock lk( tail_mtx_);
typename node_type::ptr tmp = tail_;
return tmp;
}
typename node_type::ptr pop_head_()
{
typename node_type::ptr old_head = head_;
head_ = old_head->next;
return old_head;
}
public:
unbounded_channel_base() :
state_( ACTIVE),
head_( new node_type() ),
head_mtx_(),
tail_( head_),
tail_mtx_(),
not_empty_cond_(),
use_count_( 0)
{}
bool active() const
{ return active_(); }
void deactivate()
{
mutex::scoped_lock lk( head_mtx_);
deactivate_();
not_empty_cond_.notify_all();
}
bool empty() const
{
mutex::scoped_lock lk( head_mtx_);
return empty_();
}
void put( T const& t)
{
typename node_type::ptr new_node( new node_type() );
{
mutex::scoped_lock lk( tail_mtx_);
if ( ! active_() )
throw std::runtime_error("queue is not active");
tail_->va = t;
tail_->next = new_node;
tail_ = new_node;
}
not_empty_cond_.notify_one();
}
bool take( value_type & va)
{
mutex::scoped_lock lk( head_mtx_);
bool empty = empty_();
if ( ! active_() && empty)
return false;
if ( empty)
{
try
{
while ( active_() && empty_() )
not_empty_cond_.wait( lk);
}
catch ( task_interrupted const&)
{ return false; }
}
if ( ! active_() && empty_() )
return false;
swap( va, head_->va);
pop_head_();
return va;
}
bool take( value_type & va, system_time const& abs_time)
{
mutex::scoped_lock lk( head_mtx_);
bool empty = empty_();
if ( ! active_() && empty)
return false;
if ( empty)
{
try
{
while ( active_() && empty_() )
if ( ! not_empty_cond_.timed_wait( lk, abs_time) )
return false;
}
catch ( task_interrupted const&)
{ return false; }
}
if ( ! active_() && empty_() )
return false;
swap( va, head_->va);
pop_head_();
return va;
}
bool try_take( value_type & va)
{
mutex::scoped_lock lk( head_mtx_);
if ( empty_() )
return false;
swap( va, head_->va);
pop_head_();
return va;
}
};
template< typename T >
void intrusive_ptr_add_ref( unbounded_channel_base< T > * p)
{ p->use_count_.fetch_add( 1, memory_order_relaxed); }
template< typename T >
void intrusive_ptr_release( unbounded_channel_base< T > * p)
{
if ( p->use_count_.fetch_sub( 1, memory_order_release) == 1)
{
atomic_thread_fence( memory_order_acquire);
delete p;
}
}
}
template< typename T >
class unbounded_channel
{
private:
typedef typename detail::unbounded_channel_base< T >::value_type value_type;
intrusive_ptr< detail::unbounded_channel_base< T > > base_;
public:
unbounded_channel() :
base_( new detail::unbounded_channel_base< T >() )
{}
bool active() const
{ return base_->active(); }
void deactivate()
{ base_->deactivate(); }
bool empty()
{ return base_->empty(); }
void put( T const& t)
{ base_->put( t); }
bool take( value_type & va)
{ return base_->take( va); }
bool take( value_type & va, system_time const& abs_time)
{ return base_->take( va, abs_time); }
template< typename TimeDuration >
bool take( value_type & va, TimeDuration const& rel_time)
{ return base_->take( va, get_system_time() + rel_time); }
bool try_take( value_type & va)
{ return base_->try_take( va); }
};
}}}
#include <boost/config/abi_suffix.hpp>
#endif // BOOST_TASKS_SPIN_UNBOUNDED_CHANNEL_H

View File

@@ -1,43 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKS_STACKSIZE_H
#define BOOST_TASKS_STACKSIZE_H
#include <cstddef>
#include <boost/task/detail/config.hpp>
#include <boost/config/abi_prefix.hpp>
# if defined(BOOST_MSVC)
# pragma warning(push)
# pragma warning(disable:4251 4275)
# endif
namespace boost {
namespace tasks {
class BOOST_TASKS_DECL stacksize
{
private:
std::size_t value_;
public:
explicit stacksize( std::size_t value);
operator std::size_t () const;
};
}}
# if defined(BOOST_MSVC)
# pragma warning(pop)
# endif
#include <boost/config/abi_suffix.hpp>
#endif // BOOST_TASKS_STACKSIZE_H

View File

@@ -1,208 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKS_STATIC_POOL_H
#define BOOST_TASKS_STATIC_POOL_H
#include <cstddef>
#include <boost/config.hpp>
#include <boost/tasklet/tasklet.hpp>
#include <boost/tasklet/round_robin.hpp>
#include <boost/intrusive_ptr.hpp>
#include <boost/move/move.hpp>
#include <boost/task/detail/bind_processor.hpp>
#include <boost/task/detail/pool_base.hpp>
#include <boost/task/detail/worker_group.hpp>
#include <boost/task/exceptions.hpp>
#include <boost/task/handle.hpp>
#include <boost/task/poolsize.hpp>
#include <boost/task/stacksize.hpp>
#include <boost/task/task.hpp>
#include <boost/task/watermark.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost {
namespace tasks {
template<
typename Queue,
typename UMS = tasklets::round_robin
>
class static_pool
{
public:
typedef Queue queue_type;
typedef UMS ums_type;
private:
typedef detail::pool_base< queue_type, ums_type > base_type;
template< typename T, typename X >
friend class detail::worker_object;
BOOST_MOVABLE_BUT_NOT_COPYABLE( static_pool);
# if defined(BOOST_HAS_PROCESSOR_BINDINGS)
struct tag_bind_to_processors {};
# endif
intrusive_ptr< base_type > pool_;
public:
static_pool() :
pool_()
{}
explicit static_pool(
poolsize const& psize,
stacksize const& stack_size = stacksize( tasklet::default_stacksize) ) :
pool_( new base_type( psize, stack_size) )
{}
explicit static_pool(
poolsize const& psize,
high_watermark const& hwm,
low_watermark const& lwm,
stacksize const& stack_size = stacksize( tasklet::default_stacksize) ) :
pool_( new base_type( psize, hwm, lwm, stack_size) )
{}
# if defined(BOOST_HAS_PROCESSOR_BINDINGS)
explicit static_pool(
tag_bind_to_processors,
stacksize const& stack_size = stacksize( tasklet::default_stacksize) ) :
pool_( new base_type( stack_size) )
{}
explicit static_pool(
tag_bind_to_processors,
high_watermark const& hwm,
low_watermark const& lwm,
stacksize const& stack_size = stacksize( tasklet::default_stacksize) ) :
pool_( new base_type( hwm, lwm, stack_size) )
{}
static tag_bind_to_processors bind_to_processors()
{ return tag_bind_to_processors(); }
# endif
static_pool( BOOST_RV_REF( static_pool) other) :
pool_()
{ pool_.swap( other.pool_); }
static_pool & operator=( BOOST_RV_REF( static_pool) other)
{
static_pool tmp( other);
swap( tmp);
return * this;
}
void interrupt_all_worker()
{
if ( ! pool_)
throw pool_moved();
pool_->interrupt_all_worker();
}
void shutdown()
{
if ( ! pool_)
throw pool_moved();
pool_->shutdown();
}
const void shutdown_now()
{
if ( ! pool_)
throw pool_moved();
pool_->shutdown_now();
}
std::size_t size()
{
if ( ! pool_)
throw pool_moved();
return pool_->size();
}
bool closed()
{
if ( ! pool_)
throw pool_moved();
return pool_->closed();
}
std::size_t upper_bound()
{
if ( ! pool_)
throw pool_moved();
return pool_->upper_bound();
}
void upper_bound( high_watermark const& hwm)
{
if ( ! pool_)
throw pool_moved();
pool_->upper_bound( hwm);
}
std::size_t lower_bound()
{
if ( ! pool_)
throw pool_moved();
return pool_->lower_bound();
}
void lower_bound( low_watermark const lwm)
{
if ( ! pool_)
throw pool_moved();
pool_->lower_bound( lwm);
}
template< typename R >
handle< R > submit( task< R > t)
{
if ( ! pool_)
throw pool_moved();
return pool_->submit( boost::move( t) );
}
template< typename R, typename Attr >
handle< R > submit( task< R > t, Attr const& attr)
{
if ( ! pool_)
throw pool_moved();
return pool_->submit( boost::move( t), attr);
}
typedef typename shared_ptr< base_type >::unspecified_bool_type unspecified_bool_type;
operator unspecified_bool_type() const // throw()
{ return pool_; }
bool operator!() const // throw()
{ return ! pool_; }
void swap( static_pool & other) // throw()
{ pool_.swap( other.pool_); }
};
}
template< typename Queue, typename UMS >
void swap( tasks::static_pool< Queue, UMS > & l, tasks::static_pool< Queue, UMS > & r)
{ return l.swap( r); }
}
#include <boost/config/abi_suffix.hpp>
#endif // BOOST_TASKS_STATIC_POOL_H

View File

@@ -1,497 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKS_TASK_H
#define BOOST_TASKS_TASK_H
#include <boost/atomic.hpp>
#include <boost/bind.hpp>
#include <boost/config.hpp>
#include <boost/exception_ptr.hpp>
#include <boost/intrusive_ptr.hpp>
#include <boost/move/move.hpp>
#include <boost/preprocessor/repetition.hpp>
#include <boost/thread.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/utility/result_of.hpp>
#include <boost/task/exceptions.hpp>
#include <boost/task/spin/future.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost {
namespace tasks {
namespace detail {
template< typename R >
struct promise_adaptor
{
template< typename X >
friend void intrusive_ptr_add_ref( promise_adaptor< X > *);
template< typename X >
friend void intrusive_ptr_release( promise_adaptor< X > *);
typedef intrusive_ptr< promise_adaptor > ptr;
atomic< unsigned int > use_count;
virtual ~promise_adaptor() {}
virtual void set_value(
typename tasks::detail::future_traits< R >::source_reference_type) = 0;
virtual void set_value(
typename tasks::detail::future_traits< R >::rvalue_source_type) = 0;
virtual void set_exception( exception_ptr) = 0;
};
template<>
struct promise_adaptor< void >
{
template< typename X >
friend void intrusive_ptr_add_ref( promise_adaptor< X > *);
template< typename X >
friend void intrusive_ptr_release( promise_adaptor< X > *);
typedef intrusive_ptr< promise_adaptor > ptr;
atomic< unsigned int > use_count;
virtual ~promise_adaptor() {}
virtual void set_value() = 0;
virtual void set_exception( exception_ptr) = 0;
};
template< typename R >
void intrusive_ptr_add_ref( promise_adaptor< R > * p)
{ p->use_count.fetch_add( 1, memory_order_relaxed); }
template< typename R >
void intrusive_ptr_release( promise_adaptor< R > * p)
{
if ( p->use_count.fetch_sub( 1, memory_order_release) == 1)
{
atomic_thread_fence( memory_order_acquire);
delete p;
}
}
template< typename R, template< typename > class Promise >
class promise_wrapper;
template< typename R >
class promise_wrapper< R, promise > : public promise_adaptor< R >
{
private:
promise< R > prom_;
public:
#ifdef BOOST_HAS_RVALUE_REFS
promise_wrapper( promise< R > && prom) :
prom_( prom)
{}
#else
promise_wrapper( boost::detail::thread_move_t< promise< R > > prom) :
prom_( prom)
{}
#endif
void set_value(
typename tasks::detail::future_traits< R >::source_reference_type r)
{ prom_.set_value( r); };
void set_value(
typename tasks::detail::future_traits< R >::rvalue_source_type r)
{ prom_.set_value( r); };
void set_exception( exception_ptr p)
{ prom_.set_exception( p); }
};
template<>
class promise_wrapper< void, promise > : public promise_adaptor< void >
{
private:
promise< void > prom_;
public:
#ifdef BOOST_HAS_RVALUE_REFS
promise_wrapper( promise< void > && prom) :
prom_( prom)
{}
#else
promise_wrapper( boost::detail::thread_move_t< promise< void > > prom) :
prom_( prom)
{}
#endif
void set_value()
{ prom_.set_value(); };
void set_exception( exception_ptr p)
{ prom_.set_exception( p); }
};
template< typename R >
class promise_wrapper< R, spin::promise > : public promise_adaptor< R >
{
private:
spin::promise< R > prom_;
public:
promise_wrapper() :
prom_()
{}
promise_wrapper( BOOST_RV_REF( spin::promise< R >) prom) :
prom_( prom)
{}
void set_value(
typename tasks::detail::future_traits< R >::source_reference_type r)
{ prom_.set_value( r); };
void set_value(
typename tasks::detail::future_traits< R >::rvalue_source_type r)
{ prom_.set_value( r); };
void set_exception( exception_ptr p)
{ prom_.set_exception( p); }
};
template<>
class promise_wrapper< void, spin::promise > : public promise_adaptor< void >
{
private:
spin::promise< void > prom_;
public:
promise_wrapper() :
prom_()
{}
promise_wrapper( BOOST_RV_REF( spin::promise< void >) prom) :
prom_( prom)
{}
void set_value()
{ prom_.set_value(); };
void set_exception( exception_ptr p)
{ prom_.set_exception( p); }
};
template< typename R >
class task_base
{
private:
template< typename X >
friend void intrusive_ptr_add_ref( task_base< X > *);
template< typename X >
friend void intrusive_ptr_release( task_base< X > *);
atomic< unsigned int > use_count_;
protected:
bool done_;
typename promise_adaptor< R >::ptr prom_;
virtual void do_run() = 0;
public:
task_base() :
done_( false),
prom_( new promise_wrapper< R, spin::promise >() )
{}
virtual ~task_base() {}
void run()
{
if ( this->done_) throw task_already_executed();
do_run();
done_ = true;
}
void set_promise( typename promise_adaptor< R >::ptr prom)
{ prom_ = prom; }
};
template< typename R >
void intrusive_ptr_add_ref( task_base< R > * p)
{ p->use_count_.fetch_add( 1, memory_order_relaxed); }
template< typename R >
void intrusive_ptr_release( task_base< R > * p)
{
if ( p->use_count_.fetch_sub( 1, memory_order_release) == 1)
{
atomic_thread_fence( memory_order_acquire);
delete p;
}
}
template< typename R, typename Fn >
class task_wrapper : public task_base< R >
{
private:
Fn fn_;
void do_run()
{
try
{ this->prom_->set_value( fn_() ); }
catch ( promise_already_satisfied const&)
{ throw task_already_executed(); }
catch ( thread_interrupted const&)
{ this->prom_->set_exception( copy_exception( task_interrupted() ) ); }
catch ( task_interrupted const& e)
{ this->prom_->set_exception( copy_exception( e) ); }
catch ( boost::exception const& e)
{ this->prom_->set_exception( copy_exception( e) ); }
catch ( std::ios_base::failure const& e)
{ this->prom_->set_exception( copy_exception( e) ); }
catch ( std::domain_error const& e)
{ this->prom_->set_exception( copy_exception( e) ); }
catch ( std::invalid_argument const& e)
{ this->prom_->set_exception( copy_exception( e) ); }
catch ( std::length_error const& e)
{ this->prom_->set_exception( copy_exception( e) ); }
catch ( std::out_of_range const& e)
{ this->prom_->set_exception( copy_exception( e) ); }
catch ( std::logic_error const& e)
{ this->prom_->set_exception( copy_exception( e) ); }
catch ( std::overflow_error const& e)
{ this->prom_->set_exception( copy_exception( e) ); }
catch ( std::range_error const& e)
{ this->prom_->set_exception( copy_exception( e) ); }
catch ( std::underflow_error const& e)
{ this->prom_->set_exception( copy_exception( e) ); }
catch ( std::runtime_error const& e)
{ this->prom_->set_exception( copy_exception( e) ); }
catch ( std::bad_alloc const& e)
{ this->prom_->set_exception( copy_exception( e) ); }
catch ( std::bad_cast const& e)
{ this->prom_->set_exception( copy_exception( e) ); }
catch ( std::bad_typeid const& e)
{ this->prom_->set_exception( copy_exception( e) ); }
catch ( std::bad_exception const& e)
{ this->prom_->set_exception( copy_exception( e) ); }
catch (...)
{ this->prom_->set_exception( current_exception() ); }
}
public:
task_wrapper( Fn const& fn) :
task_base< R >(), fn_( fn)
{}
};
template< typename Fn >
class task_wrapper< void, Fn > : public task_base< void >
{
private:
Fn fn_;
void do_run()
{
try
{
fn_();
this->prom_->set_value();
}
catch ( promise_already_satisfied const&)
{ throw task_already_executed(); }
catch ( thread_interrupted const&)
{ this->prom_->set_exception( copy_exception( task_interrupted() ) ); }
catch ( task_interrupted const& e)
{ this->prom_->set_exception( copy_exception( e) ); }
catch ( boost::exception const& e)
{ this->prom_->set_exception( copy_exception( e) ); }
catch ( std::ios_base::failure const& e)
{ this->prom_->set_exception( copy_exception( e) ); }
catch ( std::domain_error const& e)
{ this->prom_->set_exception( copy_exception( e) ); }
catch ( std::invalid_argument const& e)
{ this->prom_->set_exception( copy_exception( e) ); }
catch ( std::length_error const& e)
{ this->prom_->set_exception( copy_exception( e) ); }
catch ( std::out_of_range const& e)
{ this->prom_->set_exception( copy_exception( e) ); }
catch ( std::logic_error const& e)
{ this->prom_->set_exception( copy_exception( e) ); }
catch ( std::overflow_error const& e)
{ this->prom_->set_exception( copy_exception( e) ); }
catch ( std::range_error const& e)
{ this->prom_->set_exception( copy_exception( e) ); }
catch ( std::underflow_error const& e)
{ this->prom_->set_exception( copy_exception( e) ); }
catch ( std::runtime_error const& e)
{ this->prom_->set_exception( copy_exception( e) ); }
catch ( std::bad_alloc const& e)
{ this->prom_->set_exception( copy_exception( e) ); }
catch ( std::bad_cast const& e)
{ this->prom_->set_exception( copy_exception( e) ); }
catch ( std::bad_typeid const& e)
{ this->prom_->set_exception( copy_exception( e) ); }
catch ( std::bad_exception const& e)
{ this->prom_->set_exception( copy_exception( e) ); }
catch (...)
{ this->prom_->set_exception( current_exception() ); }
}
public:
task_wrapper( Fn const& fn) :
task_base< void >(), fn_( fn)
{}
};
}
template< typename R >
class task
{
private:
template< typename T, typename P >
friend class detail::callable_object;
BOOST_MOVABLE_BUT_NOT_COPYABLE( task);
intrusive_ptr< detail::task_base< R > > task_;
// TODO: if boost.thread uses boost.move
// re-work set_promise
#ifdef BOOST_HAS_RVALUE_REFS
void set_promise( promise< R > && prom)
{
if ( ! task_) throw task_moved();
task_->set_promise(
new detail::promise_wrapper< R, promise >( prom) );
}
#else
void set_promise( boost::detail::thread_move_t< promise< R > > prom)
{
if ( ! task_) throw task_moved();
task_->set_promise(
new detail::promise_wrapper< R, promise >( prom) );
}
#endif
void set_promise( BOOST_RV_REF( spin::promise< R >) prom)
{
if ( ! task_) throw task_moved();
task_->set_promise(
new detail::promise_wrapper< R, spin::promise >( prom) );
}
public:
task() :
task_()
{}
explicit task( R( * fn)()) :
task_( new detail::task_wrapper< R, R( *)() >( fn) )
{}
template< typename Fn >
explicit task( BOOST_RV_REF( Fn) fn) :
task_( new detail::task_wrapper< R, Fn >( fn) )
{}
task( BOOST_RV_REF( task) other) :
task_()
{ task_.swap( other.task_); }
task & operator=( BOOST_RV_REF( task) other)
{
task tmp( other);
swap( tmp);
return * this;
}
# ifndef BOOST_TASKS_MAX_ARITY
# define BOOST_TASKS_MAX_ARITY 10
# endif
# define BOOST_TASKS_ARG(z, n, unused) \
BOOST_PP_CAT(A, n) BOOST_PP_CAT(a, n)
# define BOOST_ENUM_TASK_ARGS(n) BOOST_PP_ENUM(n, BOOST_TASKS_ARG, ~)
# define BOOST_TASKS_CTOR(z, n, unused) \
template< \
typename Fn, \
BOOST_PP_ENUM_PARAMS(n, typename A) \
> \
explicit task( Fn fn, BOOST_ENUM_TASK_ARGS(n)) \
: task_( \
new detail::task_wrapper< R, function< R() > >( \
bind( fn, BOOST_PP_ENUM_PARAMS(n, a)) ) ) \
{}
BOOST_PP_REPEAT_FROM_TO( 1, BOOST_TASKS_MAX_ARITY, BOOST_TASKS_CTOR, ~)
# undef BOOST_TASKS_CTOR
void operator()()
{
if ( ! task_) throw task_moved();
task_->run();
}
typedef typename shared_ptr< detail::task_base< R > >::unspecified_bool_type
unspecified_bool_type;
operator unspecified_bool_type() const // throw()
{ return task_; }
bool operator!() const // throw()
{ return ! task_; }
void swap( task & other) // throw()
{ task_.swap( other.task_); }
};
template< typename Fn >
task< typename result_of< Fn() >::type > make_task( Fn fn)
{ return task< typename boost::result_of< Fn() >::type >( fn); }
# define BOOST_TASKS_MAKE_TASK_FUNCTION(z, n, unused) \
template< \
typename Fn, \
BOOST_PP_ENUM_PARAMS(n, typename A) \
> \
task< typename result_of< Fn( BOOST_PP_ENUM_PARAMS(n, A)) >::type > \
make_task( Fn fn, BOOST_ENUM_TASK_ARGS(n)) \
{ \
return task< \
typename result_of< Fn( BOOST_PP_ENUM_PARAMS(n, A)) >::type >( \
fn, BOOST_PP_ENUM_PARAMS(n, a)); \
}
BOOST_PP_REPEAT_FROM_TO(1,BOOST_TASKS_MAX_ARITY,BOOST_TASKS_MAKE_TASK_FUNCTION, ~)
# undef BOOST_TASKS_MAKE_TASK_FUNCTION
# undef BOOST_ENUM_TASK_ARGS
# undef BOOST_TASKS_ARG
# undef BOOST_TASKS_MAX_ARITY
}
using tasks::task;
template< typename R >
void swap( task< R > & l, task< R > & r)
{ return l.swap( r); }
}
#include <boost/config/abi_suffix.hpp>
#endif // BOOST_TASKS_TASK_H

View File

@@ -1,135 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKS_UNBOUNDED_FIFO_H
#define BOOST_TASKS_UNBOUNDED_FIFO_H
#include <cstddef>
#include <boost/assert.hpp>
#include <boost/atomic.hpp>
#include <boost/bind.hpp>
#include <boost/foreach.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/shared_mutex.hpp>
#include <boost/task/callable.hpp>
#include <boost/task/detail/meta.hpp>
#include <boost/task/exceptions.hpp>
#include <boost/task/fast_semaphore.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost {
namespace tasks {
class unbounded_fifo
{
public:
typedef detail::has_no_attribute attribute_tag_type;
typedef callable value_type;
private:
struct node
{
typedef shared_ptr< node > sptr_t;
value_type va;
sptr_t next;
};
enum state
{
ACTIVE = 0,
DEACTIVE
};
atomic< state > state_;
node::sptr_t head_;
mutable mutex head_mtx_;
node::sptr_t tail_;
mutable mutex tail_mtx_;
fast_semaphore & fsem_;
bool active_() const
{ return ACTIVE == state_.load(); }
void deactivate_()
{ state_.store( DEACTIVE); }
bool empty_() const
{ return head_ == get_tail_(); }
node::sptr_t get_tail_() const
{
lock_guard< mutex > lk( tail_mtx_);
node::sptr_t tmp = tail_;
return tmp;
}
node::sptr_t pop_head_()
{
node::sptr_t old_head = head_;
head_ = old_head->next;
return old_head;
}
public:
unbounded_fifo( fast_semaphore & fsem) :
state_( ACTIVE),
head_( new node),
head_mtx_(),
tail_( head_),
tail_mtx_(),
fsem_( fsem)
{}
bool active() const
{ return active_(); }
void deactivate()
{
unique_lock< mutex > lk( head_mtx_);
deactivate_();
}
bool empty() const
{
unique_lock< mutex > lk( head_mtx_);
return empty_();
}
void put( value_type const& va)
{
node::sptr_t new_node( new node);
{
unique_lock< mutex > lk( tail_mtx_);
if ( ! active_() )
throw task_rejected("queue is not active");
tail_->va = va;
tail_->next = new_node;
tail_ = new_node;
}
fsem_.post();
}
bool try_take( value_type & va)
{
unique_lock< mutex > lk( head_mtx_);
if ( empty_() )
return false;
va.swap( head_->va);
pop_head_();
return ! va.empty();
}
};
}}
#include <boost/config/abi_suffix.hpp>
#endif // BOOST_TASKS_UNBOUNDED_FIFO_H

View File

@@ -1,152 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKS_UNBOUNDED_PRIO_QUEUE_H
#define BOOST_TASKS_UNBOUNDED_PRIO_QUEUE_H
#include <algorithm>
#include <cstddef>
#include <functional>
#include <queue>
#include <boost/assert.hpp>
#include <boost/atomic.hpp>
#include <boost/bind.hpp>
#include <boost/foreach.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/shared_mutex.hpp>
#include <boost/task/callable.hpp>
#include <boost/task/detail/meta.hpp>
#include <boost/task/exceptions.hpp>
#include <boost/task/fast_semaphore.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost {
namespace tasks {
template<
typename Attr,
typename Comp = std::less< Attr >
>
class unbounded_prio_queue
{
public:
typedef detail::has_attribute attribute_tag_type;
typedef Attr attribute_type;
struct value_type
{
callable ca;
attribute_type attr;
value_type(
callable const& ca_,
attribute_type const& attr_) :
ca( ca_), attr( attr_)
{ BOOST_ASSERT( ! ca.empty() ); }
void swap( value_type & other)
{
ca.swap( other.ca);
std::swap( attr, other.attr);
}
};
private:
struct compare : public std::binary_function< value_type, value_type, bool >
{
bool operator()( value_type const& va1, value_type const& va2)
{ return Comp()( va1.attr, va2.attr); }
};
typedef std::priority_queue<
value_type,
std::deque< value_type >,
compare
> queue_type;
enum state
{
ACTIVE = 0,
DEACTIVE
};
atomic< state > state_;
queue_type queue_;
mutable shared_mutex mtx_;
fast_semaphore & fsem_;
bool active_() const
{ return ACTIVE == state_.load(); }
void deactivate_()
{ state_.store( DEACTIVE); }
bool empty_() const
{ return queue_.empty(); }
void put_( value_type const& va)
{
if ( ! active_() )
throw task_rejected("queue is not active");
queue_.push( va);
fsem_.post();
}
bool try_take_( callable & ca)
{
if ( empty_() )
return false;
callable tmp( queue_.top().ca);
queue_.pop();
ca.swap( tmp);
return ! ca.empty();
}
public:
unbounded_prio_queue( fast_semaphore & fsem) :
state_( ACTIVE),
queue_(),
mtx_(),
fsem_( fsem)
{}
bool active() const
{ return active_(); }
void deactivate()
{
unique_lock< shared_mutex > lk( mtx_);
deactivate_();
}
bool empty() const
{
shared_lock< shared_mutex > lk( mtx_);
return empty_();
}
void put( value_type const& va)
{
unique_lock< shared_mutex > lk( mtx_);
put_( va);
}
bool try_take( callable & ca)
{
unique_lock< shared_mutex > lk( mtx_);
return try_take_( ca);
}
};
}}
#include <boost/config/abi_suffix.hpp>
#endif // BOOST_TASKS_UNBOUNDED_PRIO_QUEUE_H

View File

@@ -1,163 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKS_UNBOUNDED_SMART_QUEUE_H
#define BOOST_TASKS_UNBOUNDED_SMART_QUEUE_H
#include <algorithm>
#include <cstddef>
#include <boost/assert.hpp>
#include <boost/atomic.hpp>
#include <boost/bind.hpp>
#include <boost/foreach.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/shared_mutex.hpp>
#include <boost/task/callable.hpp>
#include <boost/task/detail/meta.hpp>
#include <boost/task/detail/smart.hpp>
#include <boost/task/exceptions.hpp>
#include <boost/task/fast_semaphore.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost {
namespace tasks {
template<
typename Attr,
typename Comp,
typename Enq = detail::replace_oldest,
typename Deq = detail::take_oldest
>
class unbounded_smart_queue
{
public:
typedef detail::has_attribute attribute_tag_type;
typedef Attr attribute_type;
struct value_type
{
callable ca;
attribute_type attr;
value_type(
callable const& ca_,
attribute_type const& attr_) :
ca( ca_), attr( attr_)
{ BOOST_ASSERT( ! ca.empty() ); }
void swap( value_type & other)
{
ca.swap( other.ca);
std::swap( attr, other.attr);
}
};
private:
typedef multi_index::multi_index_container<
value_type,
multi_index::indexed_by<
multi_index::ordered_non_unique<
multi_index::member<
value_type,
Attr,
& value_type::attr
>,
Comp
>
>
> queue_type;
typedef typename queue_type::template nth_index< 0 >::type queue_index;
enum state
{
ACTIVE = 0,
DEACTIVE
};
atomic< state > state_;
queue_type queue_;
queue_index & idx_;
mutable shared_mutex mtx_;
Enq enq_op_;
Deq deq_op_;
fast_semaphore & fsem_;
bool active_() const
{ return ACTIVE == state_.load(); }
void deactivate_()
{ state_.store( DEACTIVE); }
bool empty_() const
{ return queue_.empty(); }
void put_( value_type const& va)
{
if ( ! active_() )
throw task_rejected("queue is not active");
enq_op_( idx_, va);
fsem_.post();
}
bool try_take_( callable & ca)
{
if ( empty_() )
return false;
deq_op_( idx_, ca);
return ! ca.empty();
}
public:
unbounded_smart_queue( fast_semaphore & fsem) :
state_( ACTIVE),
queue_(),
idx_( queue_.get< 0 >() ),
mtx_(),
enq_op_(),
deq_op_(),
fsem_( fsem)
{}
bool active() const
{ return active_(); }
void deactivate()
{
unique_lock< shared_mutex > lk( mtx_);
deactivate_();
}
bool empty() const
{
shared_lock< shared_mutex > lk( mtx_);
return empty_();
}
void put( value_type const& va)
{
unique_lock< shared_mutex > lk( mtx_);
put_( va);
}
bool try_take( callable & ca)
{
unique_lock< shared_mutex > lk( mtx_);
return try_take_( ca);
}
};
}}
#include <boost/config/abi_suffix.hpp>
#endif // BOOST_TASKS_UNBOUNDED_SMART_QUEUE_H

View File

@@ -1,44 +0,0 @@
// Copyright Oliver Kowalke 2009.
// 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)txt)
#ifndef BOOST_TASKS_UTILITY_H
#define BOOST_TASKS_UTILITY_H
#include <boost/assert.hpp>
#include <boost/thread.hpp>
#include <boost/task/detail/worker.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost {
namespace this_task {
inline
void yield()
{
tasks::detail::worker * w( tasks::detail::worker::tss_get() );
BOOST_ASSERT( w);
w->yield();
}
inline
bool runs_in_pool()
{ return tasks::detail::worker::tss_get() != 0; }
inline
thread::id worker_id()
{
tasks::detail::worker * w( tasks::detail::worker::tss_get() );
BOOST_ASSERT( w);
return w->get_id();
}
}}
#include <boost/config/abi_suffix.hpp>
#endif // BOOST_TASKS_UTILITY_H

View File

@@ -1,54 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKS_WATER_MARK_H
#define BOOST_TASKS_WATER_MARK_H
#include <cstddef>
#include <boost/task/detail/config.hpp>
#include <boost/config/abi_prefix.hpp>
# if defined(BOOST_MSVC)
# pragma warning(push)
# pragma warning(disable:4251 4275)
# endif
namespace boost {
namespace tasks {
class BOOST_TASKS_DECL high_watermark
{
private:
std::size_t value_;
public:
explicit high_watermark( std::size_t value);
operator std::size_t () const;
};
class BOOST_TASKS_DECL low_watermark
{
private:
std::size_t value_;
public:
explicit low_watermark( std::size_t value);
operator std::size_t () const;
};
}}
# if defined(BOOST_MSVC)
# pragma warning(pop)
# endif
#include <boost/config/abi_suffix.hpp>
#endif // BOOST_TASKS_WATER_MARK_H

View File

@@ -1,27 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKLET_H
#define BOOST_TASKLET_H
#include <boost/tasklet/auto_reset_event.hpp>
#include <boost/tasklet/barrier.hpp>
#include <boost/tasklet/bounded_channel.hpp>
#include <boost/tasklet/condition.hpp>
#include <boost/tasklet/count_down_event.hpp>
#include <boost/tasklet/exceptions.hpp>
#include <boost/tasklet/interruption.hpp>
#include <boost/tasklet/manual_reset_event.hpp>
#include <boost/tasklet/mutex.hpp>
#include <boost/tasklet/scheduler.hpp>
#include <boost/tasklet/spin_condition.hpp>
#include <boost/tasklet/spin_mutex.hpp>
#include <boost/tasklet/strategy.hpp>
#include <boost/tasklet/tasklet.hpp>
#include <boost/tasklet/unbounded_channel.hpp>
#include <boost/tasklet/utility.hpp>
#endif // BOOST_TASKLET_H

View File

@@ -1,59 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKLETS_AUTO_RESET_EVENT_H
#define BOOST_TASKLETS_AUTO_RESET_EVENT_H
#include <boost/atomic.hpp>
#include <boost/config.hpp>
#include <boost/utility.hpp>
#include <boost/tasklet/detail/config.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
# if defined(BOOST_MSVC)
# pragma warning(push)
# pragma warning(disable:4355 4251 4275)
# endif
namespace boost {
namespace tasklets {
class BOOST_TASKLET_DECL auto_reset_event : private noncopyable
{
private:
enum state
{
SET = 0,
RESET
};
atomic< state > state_;
public:
explicit auto_reset_event( bool = false);
void set();
void wait();
bool try_wait();
};
}}
# if defined(BOOST_MSVC)
# pragma warning(pop)
# endif
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_TASKLETS_AUTO_RESET_EVENT_H

View File

@@ -1,56 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKLETS_BARRIER_H
#define BOOST_TASKLETS_BARRIER_H
#include <cstddef>
#include <boost/config.hpp>
#include <boost/utility.hpp>
#include <boost/tasklet/detail/config.hpp>
#include <boost/tasklet/condition.hpp>
#include <boost/tasklet/mutex.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
# if defined(BOOST_MSVC)
# pragma warning(push)
# pragma warning(disable:4275)
# endif
namespace boost {
namespace tasklets {
class BOOST_TASKLET_DECL barrier : private noncopyable
{
private:
std::size_t initial_;
std::size_t current_;
bool cycle_;
mutex mtx_;
condition cond_;
public:
barrier( std::size_t);
bool wait();
};
}}
# if defined(BOOST_MSVC)
# pragma warning(pop)
# endif
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_TASKLETS_BARRIER_H

View File

@@ -1,265 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKLETS_BOUNDED_CHANNEL_H
#define BOOST_TASKLETS_BOUNDED_CHANNEL_H
#include <cstddef>
#include <stdexcept>
#include <boost/atomic.hpp>
#include <boost/config.hpp>
#include <boost/intrusive_ptr.hpp>
#include <boost/optional.hpp>
#include <boost/utility.hpp>
#include <boost/tasklet/exceptions.hpp>
#include <boost/tasklet/condition.hpp>
#include <boost/tasklet/mutex.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
namespace boost {
namespace tasklets {
namespace detail {
template< typename T >
struct bounded_channel_node
{
typedef intrusive_ptr< bounded_channel_node > ptr;
atomic< std::size_t > use_count;
T va;
ptr next;
bounded_channel_node() :
use_count( 0),
va(),
next()
{}
};
template< typename T >
void intrusive_ptr_add_ref( bounded_channel_node< T > * p)
{ p->use_count.fetch_add( 1, memory_order_relaxed); }
template< typename T >
void intrusive_ptr_release( bounded_channel_node< T > * p)
{
if ( p->use_count.fetch_sub( 1, memory_order_release) == 1)
{
atomic_thread_fence( memory_order_acquire);
delete p;
}
}
}
template< typename T >
class bounded_channel : private noncopyable
{
public:
typedef optional< T > value_type;
private:
typedef detail::bounded_channel_node< value_type > node_type;
template< typename X >
friend void intrusive_ptr_add_ref( bounded_channel< X > * p);
template< typename X >
friend void intrusive_ptr_release( bounded_channel< X > * p);
enum state
{
ACTIVE = 0,
DEACTIVE
};
atomic< state > state_;
atomic< std::size_t > count_;
typename node_type::ptr head_;
mutable mutex head_mtx_;
typename node_type::ptr tail_;
mutable mutex tail_mtx_;
condition not_empty_cond_;
condition not_full_cond_;
unsigned int hwm_;
unsigned int lwm_;
atomic< std::size_t > use_count_;
bool active_() const
{ return ACTIVE == state_.load(); }
void deactivate_()
{ state_.store( DEACTIVE); }
std::size_t size_() const
{ return count_.load(); }
bool empty_() const
{ return head_ == get_tail_(); }
bool full_() const
{ return size_() >= hwm_; }
typename node_type::ptr get_tail_() const
{
mutex::scoped_lock lk( tail_mtx_);
typename node_type::ptr tmp = tail_;
return tmp;
}
typename node_type::ptr pop_head_()
{
typename node_type::ptr old_head = head_;
head_ = old_head->next;
count_.fetch_sub( 1);
return old_head;
}
public:
bounded_channel(
std::size_t hwm,
std::size_t lwm) :
state_( ACTIVE),
count_( 0),
head_( new node_type() ),
head_mtx_(),
tail_( head_),
tail_mtx_(),
not_empty_cond_(),
not_full_cond_(),
hwm_( hwm),
lwm_( lwm),
use_count_( 0)
{
if ( hwm_ < lwm_)
throw invalid_watermark();
}
bounded_channel( std::size_t wm) :
state_( ACTIVE),
count_( 0),
head_( new node_type() ),
head_mtx_(),
tail_( head_),
tail_mtx_(),
not_empty_cond_(),
not_full_cond_(),
hwm_( wm),
lwm_( wm),
use_count_( 0)
{}
std::size_t upper_bound() const
{ return hwm_; }
std::size_t lower_bound() const
{ return lwm_; }
bool active() const
{ return active_(); }
void deactivate()
{
mutex::scoped_lock head_lk( head_mtx_);
mutex::scoped_lock tail_lk( tail_mtx_);
deactivate_();
not_empty_cond_.notify_all();
not_full_cond_.notify_all();
}
bool empty() const
{
mutex::scoped_lock lk( head_mtx_);
return empty_();
}
void put( T const& t)
{
typename node_type::ptr new_node( new node_type() );
{
mutex::scoped_lock lk( tail_mtx_);
if ( full_() )
{
while ( active_() && full_() )
not_full_cond_.wait( lk);
}
if ( ! active_() )
throw std::runtime_error("queue is not active");
tail_->va = t;
tail_->next = new_node;
tail_ = new_node;
count_.fetch_add( 1);
}
not_empty_cond_.notify_one();
}
bool take( value_type & va)
{
mutex::scoped_lock lk( head_mtx_);
bool empty = empty_();
if ( ! active_() && empty)
return false;
if ( empty)
{
try
{
while ( active_() && empty_() )
not_empty_cond_.wait( lk);
}
catch ( tasklet_interrupted const&)
{ return false; }
}
if ( ! active_() && empty_() )
return false;
swap( va, head_->va);
pop_head_();
if ( size_() <= lwm_)
{
if ( lwm_ == hwm_)
not_full_cond_.notify_one();
else
// more than one producer could be waiting
// for submiting an action object
not_full_cond_.notify_all();
}
return va;
}
bool try_take( value_type & va)
{
mutex::scoped_lock lk( head_mtx_);
if ( empty_() )
return false;
swap( va, head_->va);
pop_head_();
bool valid = va;
if ( valid && size_() <= lwm_)
{
if ( lwm_ == hwm_)
not_full_cond_.notify_one();
else
// more than one producer could be waiting
// in order to submit an task
not_full_cond_.notify_all();
}
return valid;
}
};
}}
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_TASKLETS_BOUNDED_CHANNEL_H

View File

@@ -1,198 +0,0 @@
// Copyright Oliver Kowalke 2009.
// 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)
//
// based on boost::interprocess::sync::interprocess_condition
#ifndef BOOST_TASKLETS_CONDITION_H
#define BOOST_TASKLETS_CONDITION_H
#include <cstddef>
#include <boost/assert.hpp>
#include <boost/atomic.hpp>
#include <boost/config.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/mem_fun.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/thread.hpp>
#include <boost/utility.hpp>
#include <boost/tasklet/detail/config.hpp>
#include <boost/tasklet/spin_mutex.hpp>
#include <boost/tasklet/exceptions.hpp>
#include <boost/tasklet/mutex.hpp>
#include <boost/tasklet/utility.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
# if defined(BOOST_MSVC)
# pragma warning(push)
# pragma warning(disable:4355 4251 4275)
# endif
namespace boost {
namespace tasklets {
class BOOST_TASKLET_DECL condition : private noncopyable
{
private:
enum command
{
SLEEPING = 0,
NOTIFY_ONE,
NOTIFY_ALL
};
struct ordered_idx_tag {};
struct sequenced_idx_tag {};
typedef boost::multi_index::multi_index_container<
tasklet,
boost::multi_index::indexed_by<
boost::multi_index::ordered_unique<
boost::multi_index::tag< ordered_idx_tag >,
boost::multi_index::const_mem_fun<
tasklet, tasklet::id, & tasklet::get_id
>
>,
boost::multi_index::sequenced<
boost::multi_index::tag< sequenced_idx_tag >
>
>
> container;
typedef container::index< ordered_idx_tag >::type ordered_idx;
typedef container::index< sequenced_idx_tag >::type sequenced_idx;
object::id oid_;
container waiting_tasklets_;
ordered_idx & oidx_;
sequenced_idx & sidx_;
atomic< command > cmd_;
atomic< std::size_t > waiters_;
mutex enter_mtx_;
mutex check_mtx_;
spin_mutex mtx_;
public:
condition();
~condition();
void notify_one();
void notify_all();
void wait( unique_lock< mutex > & lk)
{
if ( ! lk)
throw lock_error();
wait( * lk.mutex() );
}
template< typename Pred >
void wait( unique_lock< mutex > & lk, Pred pred)
{
if ( ! lk)
throw lock_error();
while ( ! pred() )
wait( * lk.mutex() );
}
template< typename LockType >
void wait( LockType & lt)
{
{
mutex::scoped_lock lk( enter_mtx_);
BOOST_ASSERT( lk);
waiters_.fetch_add( 1);
lt.unlock();
}
bool unlock_enter_mtx = false;
for (;;)
{
{
spin_mutex::scoped_lock lk( mtx_);
if ( SLEEPING == cmd_.load() )
{
if ( this_tasklet::runs_as_tasklet() )
{
tasklet * f( strategy::active_tasklet);
BOOST_ASSERT( f);
oidx_.insert( * f);
BOOST_ASSERT( f->impl_->attached_strategy() );
f->impl_->attached_strategy()->wait_for_object( oid_, lk);
continue;
}
else
{
lk.unlock();
this_thread::yield();
continue;
}
}
}
mutex::scoped_lock lk( check_mtx_);
BOOST_ASSERT( lk);
command expected = NOTIFY_ONE;
cmd_.compare_exchange_strong( expected, SLEEPING);
if ( SLEEPING == expected)
continue;
else if ( NOTIFY_ONE == expected)
{
unlock_enter_mtx = true;
waiters_.fetch_sub( 1);
break;
}
else
{
BOOST_ASSERT( NOTIFY_ALL == expected);
unlock_enter_mtx = 1 == waiters_.fetch_sub( 1);
if ( unlock_enter_mtx)
{
expected = NOTIFY_ALL;
cmd_.compare_exchange_strong( expected, SLEEPING);
}
break;
}
}
if ( unlock_enter_mtx)
enter_mtx_.unlock();
lt.lock();
}
template<
typename LockType,
typename Pred
>
void wait( LockType & lt, Pred pred)
{
while ( ! pred() )
wait( lt);
}
};
}}
# if defined(BOOST_MSVC)
# pragma warning(pop)
# endif
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_TASKLETS_CONDITION_H

View File

@@ -1,60 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKLETS_COUNT_DOWN_EVENT_H
#define BOOST_TASKLETS_COUNT_DOWN_EVENT_H
#include <cstddef>
#include <boost/atomic.hpp>
#include <boost/config.hpp>
#include <boost/utility.hpp>
#include <boost/tasklet/detail/config.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
# if defined(BOOST_MSVC)
# pragma warning(push)
# pragma warning(disable:4355 4251 4275)
# endif
namespace boost {
namespace tasklets {
class BOOST_TASKLET_DECL count_down_event : private noncopyable
{
private:
std::size_t initial_;
atomic< std::size_t > current_;
public:
explicit count_down_event( std::size_t);
std::size_t initial() const;
std::size_t current() const;
bool is_set() const;
void set();
void wait();
};
}}
# if defined(BOOST_MSVC)
# pragma warning(pop)
# endif
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_TASKLETS_COUNT_DOWN_EVENT_H

View File

@@ -1,41 +0,0 @@
// Copyright Oliver Kowalke 2009.
// 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)
// this file is based on config.hpp of boost.thread
#ifndef BOOST_TASKLETS_DETAIL_CONFIG_H
#define BOOST_TASKLETS_DETAIL_CONFIG_H
#include <boost/config.hpp>
#include <boost/detail/workaround.hpp>
#if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_TASKLET_DYN_LINK)
# if defined(BOOST_TASKLET_SOURCE)
# define BOOST_TASKLET_DECL BOOST_SYMBOL_EXPORT
# else
# define BOOST_TASKLET_DECL BOOST_SYMBOL_IMPORT
# endif
#else
# define BOOST_TASKLET_DECL
#endif
#if ! defined(BOOST_TASKLET_SOURCE) && !defined(BOOST_ALL_NO_LIB) && !defined(BOOST_TASKLET_NO_LIB)
# define BOOST_LIB_NAME boost_tasklet
# if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_TASKLET_DYN_LINK)
# define BOOST_DYN_LINK
# endif
# include <boost/config/auto_link.hpp>
#endif
#if defined(_MSC_VER)
# define BOOST_TASKLET_TSSDECL __declspec(thread)
#elif defined(__GNUC__)
# define BOOST_TASKLET_TSSDECL __thread
#else
# error "this platform is not supported"
#endif
#endif // BOOST_TASKLETS_DETAIL_CONFIG_H

View File

@@ -1,90 +0,0 @@
// (C) Copyright 2008-9 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKLETS_DETAIL_FUTURE_TRAITS_H
#define BOOST_TASKLETS_DETAIL_FUTURE_TRAITS_H
#include <algorithm>
#include <list>
#include <stdexcept>
#include <vector>
#include <boost/config.hpp>
#include <boost/move/move.hpp>
#include <boost/mpl/if.hpp>
#include <boost/next_prior.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/type_traits/is_fundamental.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
namespace boost {
namespace tasklets {
namespace detail {
template<typename T>
struct future_traits
{
typedef boost::scoped_ptr<T> storage_type;
#ifdef BOOST_HAS_RVALUE_REFS
typedef T const& source_reference_type;
struct dummy;
typedef typename boost::mpl::if_<boost::is_fundamental<T>,dummy&,T&&>::type rvalue_source_type;
typedef typename boost::mpl::if_<boost::is_fundamental<T>,T,T&&>::type move_dest_type;
#else
typedef T& source_reference_type;
typedef typename boost::mpl::if_<boost::is_convertible<T&, BOOST_RV_REF( T) >, BOOST_RV_REF( T),T const&>::type rvalue_source_type;
typedef typename boost::mpl::if_<boost::is_convertible<T&,BOOST_RV_REF( T) >,BOOST_RV_REF( T),T>::type move_dest_type;
#endif
static void init(storage_type& storage,source_reference_type t)
{ storage.reset(new T(t)); }
static void init(storage_type& storage,rvalue_source_type t)
{ storage.reset(new T(static_cast<rvalue_source_type>(t))); }
static void cleanup(storage_type& storage)
{ storage.reset(); }
};
template<typename T>
struct future_traits<T&>
{
typedef T* storage_type;
typedef T& source_reference_type;
struct rvalue_source_type {};
typedef T& move_dest_type;
static void init(storage_type& storage,T& t)
{ storage=&t; }
static void cleanup(storage_type& storage)
{ storage=0; }
};
template<>
struct future_traits<void>
{
typedef bool storage_type;
typedef void move_dest_type;
static void init(storage_type& storage)
{ storage=true; }
static void cleanup(storage_type& storage)
{ storage=false; }
};
}}}
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_TASKLETS_DETAIL_FUTURE_TRAITS_H

View File

@@ -1,35 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKLETS_DETAIL_INTERRUPT_FLAGS_H
#define BOOST_TASKLETS_DETAIL_INTERRUPT_FLAGS_H
#include <boost/config.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
namespace boost {
namespace tasklets {
namespace detail {
enum interrupt_t_
{
INTERRUPTION_DISABLED = 1 << 0,
INTERRUPTION_ENABLED = 1 << 1,
INTERRUPTION_BLOCKED = 1 << 2
};
typedef char interrupt_type;
}}}
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_TASKLETS_DETAIL_INTERRUPT_FLAGS_H

View File

@@ -1,40 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKLETS_DETAIL_STATE_FLAGS_H
#define BOOST_TASKLETS_DETAIL_STATE_FLAGS_H
#include <boost/config.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
namespace boost {
namespace tasklets {
namespace detail {
enum state_t_
{
STATE_NOT_STARTED = 1 << 0,
STATE_READY = 1 << 1,
STATE_RUNNING = 1 << 2,
STATE_WAIT_FOR_TASKLET = 1 << 3,
STATE_WAIT_FOR_OBJECT = 1 << 4,
STATE_TERMINATED = 1 << 5
};
typedef char state_type;
#define IS_ALIVE_BIT_MASK 0x1e
}}}
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_TASKLETS_DETAIL_STATE_FLAGS_H

View File

@@ -1,97 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKLETS_DETAIL_TASKLET_BASE_H
#define BOOST_TASKLETS_DETAIL_TASKLET_BASE_H
#include <cstddef>
#include <boost/config.hpp>
#include <boost/fiber.hpp>
#include <boost/intrusive_ptr.hpp>
#include <boost/utility.hpp>
#include <boost/tasklet/detail/config.hpp>
#include <boost/tasklet/detail/interrupt_flags.hpp>
#include <boost/tasklet/detail/state_flags.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
namespace boost {
namespace tasklets {
class strategy;
namespace detail {
BOOST_TASKLET_DECL void trampoline( void *);
class BOOST_TASKLET_DECL tasklet_base : private noncopyable
{
public:
typedef intrusive_ptr< tasklet_base > ptr;
friend BOOST_TASKLET_DECL void trampoline( void *);
template< typename AllocatorT >
tasklet_base( std::size_t stacksize, AllocatorT const& alloc) :
use_count_( 0),
fib_( trampoline, this, stacksize, alloc),
priority_( 0),
state_( STATE_NOT_STARTED),
interrupt_( INTERRUPTION_DISABLED),
st_( 0)
{}
virtual ~tasklet_base() {}
void run();
void yield();
int priority() const;
void priority( int);
state_type state() const;
void state( state_type);
interrupt_type & interrupt();
void interrupt( interrupt_type);
strategy * attached_strategy();
void attached_strategy( strategy *);
friend inline void intrusive_ptr_add_ref( tasklet_base * p)
{ ++( p->use_count_); }
friend inline void intrusive_ptr_release( tasklet_base * p)
{ if ( 0 == --( p->use_count_) ) delete p; }
protected:
virtual void exec() = 0;
private:
std::size_t use_count_;
fiber fib_;
int priority_;
state_type state_;
interrupt_type interrupt_;
strategy * st_;
};
}}}
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_TASKLETS_DETAIL_TASKLET_BASE_H

View File

@@ -1,99 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKLETS_DETAIL_TASKLET_OBJECT_H
#define BOOST_TASKLETS_DETAIL_TASKLET_OBJECT_H
#include <cstddef>
#include <boost/config.hpp>
#include <boost/move/move.hpp>
#include <boost/type_traits/remove_reference.hpp>
#include <boost/tasklet/detail/config.hpp>
#include <boost/tasklet/detail/tasklet_base.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
namespace boost {
namespace tasklets {
namespace detail {
template< typename Fn >
class tasklet_object : public tasklet_base
{
private:
Fn fn_;
tasklet_object( tasklet_object &);
tasklet_object & operator=( tasklet_object const&);
public:
template< typename AllocatorT >
tasklet_object( Fn fn, std::size_t stacksize, AllocatorT const& alloc) :
tasklet_base( stacksize, alloc),
fn_( fn)
{}
template< typename AllocatorT >
tasklet_object( BOOST_RV_REF( Fn) fn, std::size_t stacksize, AllocatorT const& alloc) :
tasklet_base( stacksize, alloc),
fn_( fn)
{}
void exec()
{ fn_(); }
};
template< typename Fn >
class tasklet_object< reference_wrapper< Fn > > : public tasklet_base
{
private:
Fn & fn_;
tasklet_object( tasklet_object &);
tasklet_object & operator=( tasklet_object const&);
public:
template< typename AllocatorT >
tasklet_object( reference_wrapper< Fn > fn, std::size_t stacksize, AllocatorT const& alloc) :
tasklet_base( stacksize, alloc),
fn_( fn)
{}
void exec()
{ fn_(); }
};
template< typename Fn >
class tasklet_object< const reference_wrapper< Fn > > : public tasklet_base
{
private:
Fn & fn_;
tasklet_object( tasklet_object &);
tasklet_object & operator=( tasklet_object const&);
public:
template< typename AllocatorT >
tasklet_object( const reference_wrapper< Fn > fn, std::size_t stacksize, AllocatorT const& alloc) :
tasklet_base( stacksize, alloc),
fn_( fn)
{}
void exec()
{ fn_(); }
};
}}}
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_TASKLETS_DETAIL_TASKLET_OBJECT_H

View File

@@ -1,127 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKLETS_EXCEPTIONS_H
#define BOOST_TASKLETS_EXCEPTIONS_H
#include <stdexcept>
#include <string>
#include <boost/config.hpp>
#include <boost/tasklet/detail/config.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
namespace boost {
namespace tasklets {
class tasklet_error : public std::runtime_error
{
public:
tasklet_error( std::string const& msg) :
std::runtime_error( msg)
{}
};
class tasklet_interrupted
{};
class tasklet_moved : public std::logic_error
{
public:
tasklet_moved() :
std::logic_error("tasklet moved")
{}
};
class invalid_watermark : public std::runtime_error
{
public:
invalid_watermark() :
std::runtime_error("invalid watermark")
{}
};
class lock_error : public std::logic_error
{
public:
lock_error() :
std::logic_error("lock invalid")
{}
};
class scheduler_error : public std::runtime_error
{
public:
scheduler_error( std::string const& msg) :
std::runtime_error( msg)
{}
};
class future_uninitialized :
public std::logic_error
{
public:
future_uninitialized() :
std::logic_error("Future Uninitialized")
{}
};
class broken_promise :
public std::logic_error
{
public:
broken_promise() :
std::logic_error("Broken promise")
{}
};
class future_already_retrieved :
public std::logic_error
{
public:
future_already_retrieved() :
std::logic_error("Future already retrieved")
{}
};
class promise_already_satisfied :
public std::logic_error
{
public:
promise_already_satisfied() :
std::logic_error("Promise already satisfied")
{}
};
class task_already_started :
public std::logic_error
{
public:
task_already_started() :
std::logic_error("Task already started")
{}
};
class task_moved :
public std::logic_error
{
public:
task_moved() :
std::logic_error("Task moved")
{}
};
}}
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_TASKLETS_EXCEPTIONS_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,86 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_THIS_TASKLET_INTERRUPTION_H
#define BOOST_THIS_TASKLET_INTERRUPTION_H
#include <cstddef>
#include <boost/config.hpp>
#include <boost/utility.hpp>
#include <boost/tasklet/detail/config.hpp>
#include <boost/tasklet/detail/interrupt_flags.hpp>
#include <boost/tasklet/strategy.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
namespace boost {
namespace this_tasklet {
class restore_interruption;
class disable_interruption : private noncopyable
{
private:
friend class restore_interruption;
bool set_;
public:
disable_interruption() :
set_( ( tasklets::strategy::interrupt_flags_() & tasklets::detail::INTERRUPTION_BLOCKED) != 0)
{
if ( ! set_)
tasklets::strategy::interrupt_flags_() |= tasklets::detail::INTERRUPTION_BLOCKED;
}
~disable_interruption()
{
try
{
if ( ! set_)
tasklets::strategy::interrupt_flags_() &= ~tasklets::detail::INTERRUPTION_BLOCKED;
}
catch (...)
{}
}
};
class restore_interruption : private noncopyable
{
private:
disable_interruption & disabler_;
public:
explicit restore_interruption( disable_interruption & disabler) :
disabler_( disabler)
{
if ( ! disabler_.set_)
tasklets::strategy::interrupt_flags_() &= ~tasklets::detail::INTERRUPTION_BLOCKED;
}
~restore_interruption()
{
try
{
if ( ! disabler_.set_)
tasklets::strategy::interrupt_flags_() |= tasklets::detail::INTERRUPTION_BLOCKED;
}
catch (...)
{}
}
};
}}
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_THIS_TASKLET_INTERRUPTION_H

View File

@@ -1,66 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKLETS_MANUAL_RESET_EVENT_H
#define BOOST_TASKLETS_MANUAL_RESET_EVENT_H
#include <cstddef>
#include <boost/atomic.hpp>
#include <boost/config.hpp>
#include <boost/utility.hpp>
#include <boost/tasklet/detail/config.hpp>
#include <boost/tasklet/mutex.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
# if defined(BOOST_MSVC)
# pragma warning(push)
# pragma warning(disable:4355 4251 4275)
# endif
namespace boost {
namespace tasklets {
class BOOST_TASKLET_DECL manual_reset_event : private noncopyable
{
private:
enum state
{
SET = 0,
RESET
};
atomic< state > state_;
atomic< std::size_t > waiters_;
mutex enter_mtx_;
public:
explicit manual_reset_event( bool = false);
void set();
void reset();
void wait();
bool try_wait();
};
}}
# if defined(BOOST_MSVC)
# pragma warning(pop)
# endif
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_TASKLETS_MANUAL_RESET_EVENT_H

View File

@@ -1,101 +0,0 @@
// Copyright Oliver Kowalke 2009.
// 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)
//
// based on boost::interprocess::sync::interprocess_spin_mutex
#ifndef BOOST_TASKLETS_MUTEX_H
#define BOOST_TASKLETS_MUTEX_H
#include <boost/atomic.hpp>
#include <boost/config.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/mem_fun.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/thread/locks.hpp>
#include <boost/utility.hpp>
#include <boost/tasklet/detail/config.hpp>
#include <boost/tasklet/spin_mutex.hpp>
#include <boost/tasklet/tasklet.hpp>
#include <boost/tasklet/object/id.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
# if defined(BOOST_MSVC)
# pragma warning(push)
# pragma warning(disable:4355 4251 4275)
# endif
namespace boost {
namespace tasklets {
class BOOST_TASKLET_DECL mutex : private noncopyable
{
private:
enum state
{
LOCKED = 0,
UNLOCKED
};
struct ordered_idx_tag {};
struct sequenced_idx_tag {};
typedef boost::multi_index::multi_index_container<
tasklet,
boost::multi_index::indexed_by<
boost::multi_index::ordered_unique<
boost::multi_index::tag< ordered_idx_tag >,
boost::multi_index::const_mem_fun<
tasklet, tasklet::id, & tasklet::get_id
>
>,
boost::multi_index::sequenced<
boost::multi_index::tag< sequenced_idx_tag >
>
>
> container;
typedef container::index< ordered_idx_tag >::type ordered_idx;
typedef container::index< sequenced_idx_tag >::type sequenced_idx;
object::id oid_;
state state_;
spin_mutex mtx_;
container waiting_tasklets_;
ordered_idx & oidx_;
sequenced_idx & sidx_;
public:
typedef unique_lock< mutex > scoped_lock;
mutex();
~mutex();
void lock();
bool try_lock();
void unlock();
};
typedef mutex try_mutex;
}}
# if defined(BOOST_MSVC)
# pragma warning(pop)
# endif
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_TASKLETS_MUTEX_H

View File

@@ -1,68 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKLETS_DETAIL_ID_H
#define BOOST_TASKLETS_DETAIL_ID_H
#include <iostream>
#include <boost/config.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
namespace boost {
namespace tasklets {
namespace object {
class id
{
private:
void const* vp_;
public:
template< typename T >
id( T const& t) :
vp_( static_cast< void const* >( & t) )
{}
bool operator==( id const& other) const
{ return vp_ == other.vp_; }
bool operator!=( id const& other) const
{ return vp_ != other.vp_; }
bool operator<( id const& other) const
{ return vp_ < other.vp_; }
bool operator>( id const& other) const
{ return other.vp_ < vp_; }
bool operator<=( id const& other) const
{ return !( other.vp_ < vp_); }
bool operator>=( id const& other) const
{ return ! ( vp_ < other.vp_); }
template< typename charT, class traitsT >
friend std::basic_ostream< charT, traitsT > &
operator<<( std::basic_ostream< charT, traitsT > & os, id const& other)
{
if ( other.vp_)
return os << other.vp_;
else
return os << "{not-a-object}";
}
};
}}}
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_TASKLETS_DETAIL_ID_H

View File

@@ -1,138 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKLETS_ROUND_ROBIN_H
#define BOOST_TASKLETS_ROUND_ROBIN_H
#include <cstddef>
#include <list>
#include <map>
#include <queue>
#include <boost/config.hpp>
#include <boost/function.hpp>
#include <boost/optional.hpp>
#include <boost/utility.hpp>
#include <boost/tasklet/detail/config.hpp>
#include <boost/tasklet/spin_mutex.hpp>
#include <boost/tasklet/object/id.hpp>
#include <boost/tasklet/tasklet.hpp>
#include <boost/tasklet/strategy.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
# if defined(BOOST_MSVC)
# pragma warning(push)
# pragma warning(disable:4251 4275)
# endif
namespace boost {
namespace tasklets {
class BOOST_TASKLET_DECL round_robin : private noncopyable,
public strategy
{
private:
struct schedulable
{
tasklet f;
std::list< tasklet::id > joining_tasklets;
optional< tasklet::id > waiting_on_tasklet;
optional< object::id > waiting_on_object;
schedulable() :
f(), joining_tasklets(),
waiting_on_tasklet(), waiting_on_object()
{}
schedulable( tasklet f_) :
f( f_), joining_tasklets(),
waiting_on_tasklet(), waiting_on_object()
{}
schedulable( schedulable const& other) :
f( other.f),
joining_tasklets( other.joining_tasklets),
waiting_on_tasklet( other.waiting_on_tasklet),
waiting_on_object( other.waiting_on_object)
{}
schedulable &
operator=( schedulable const& other)
{
if ( this == & other) return * this;
f = other.f;
joining_tasklets = other.joining_tasklets;
waiting_on_tasklet = other.waiting_on_tasklet;
waiting_on_object = other.waiting_on_object;
return * this;
}
};
typedef std::list< tasklet::id > tasklet_id_list;
typedef std::map< object::id, tasklet_id_list > object_map;
typedef std::map< tasklet::id, schedulable > tasklet_map;
typedef std::list< tasklet::id > runnable_queue;
typedef std::queue< tasklet::id > terminated_queue;
mutable spin_mutex mtx_;
tasklet_map tasklets_;
object_map objects_;
runnable_queue runnable_tasklets_;
terminated_queue terminated_tasklets_;
public:
round_robin();
void add( tasklet &);
void join( tasklet &);
void interrupt( tasklet &);
void reschedule( tasklet &);
void cancel( tasklet &);
void yield();
void wait_for_object( object::id const&, spin_mutex::scoped_lock & lk);
void object_notify_one( object::id const&);
void object_notify_all( object::id const&);
void release( tasklet &);
void migrate( tasklet &);
void detach_all();
bool run();
bool empty() const;
std::size_t size() const;
std::size_t ready() const;
bool has_ready() const;
};
}}
# if defined(BOOST_MSVC)
# pragma warning(pop)
# endif
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_TASKLETS_ROUND_ROBIN_H

View File

@@ -1,96 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKLETS_SCHEDULER_H
#define BOOST_TASKLETS_SCHEDULER_H
#include <algorithm>
#include <cstddef>
#include <boost/config.hpp>
#include <boost/utility.hpp>
#include <boost/tasklet/exceptions.hpp>
#include <boost/tasklet/tasklet.hpp>
#include <boost/tasklet/round_robin.hpp>
#include <boost/tasklet/strategy.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
namespace boost {
namespace tasklets {
class auto_reset_event;
class condition;
class count_down_event;
class manual_reset_event;
class mutex;
template< typename Strategy = round_robin >
class scheduler : private noncopyable
{
private:
friend class auto_reset_event;
friend class condition;
friend class count_down_event;
friend class manual_reset_event;
friend class mutex;
strategy * strategy_;
public:
scheduler() :
strategy_( new Strategy() )
{}
~scheduler()
{
strategy_->detach_all();
delete strategy_;
}
bool run()
{ return strategy_->run(); }
bool empty() const
{ return strategy_->empty(); }
std::size_t size() const
{ return strategy_->size(); }
std::size_t ready() const
{ return strategy_->ready(); }
bool has_ready() const
{ return strategy_->has_ready(); }
void submit_tasklet( tasklet t)
{ strategy_->add( t); }
void migrate_tasklet( tasklet & t)
{
if ( ! t) throw tasklet_moved();
t.impl_->attached_strategy()->release( t);
strategy_->migrate( t);
}
void swap( scheduler & other)
{ std::swap( strategy_, other.strategy_); }
};
template< typename Strategy >
void swap( scheduler< Strategy > & l, scheduler< Strategy > & r)
{ l.swap( r); }
}}
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_TASKLETS_SCHEDULER_H

View File

@@ -1,152 +0,0 @@
// Copyright Oliver Kowalke 2009.
// 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)
//
// based on boost::interprocess::sync::interprocess_condition
#ifndef BOOST_TASKLETS_SPIN_CONDITION_H
#define BOOST_TASKLETS_SPIN_CONDITION_H
#include <cstddef>
#include <boost/assert.hpp>
#include <boost/atomic.hpp>
#include <boost/config.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/thread.hpp>
#include <boost/utility.hpp>
#include <boost/tasklet/detail/config.hpp>
#include <boost/tasklet/spin_mutex.hpp>
#include <boost/tasklet/exceptions.hpp>
#include <boost/tasklet/utility.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
# if defined(BOOST_MSVC)
# pragma warning(push)
# pragma warning(disable:4355 4251 4275)
# endif
namespace boost {
namespace tasklets {
class BOOST_TASKLET_DECL spin_condition : private noncopyable
{
private:
enum command
{
SLEEPING = 0,
NOTIFY_ONE,
NOTIFY_ALL
};
atomic< command > cmd_;
atomic< std::size_t > waiters_;
spin_mutex enter_mtx_;
spin_mutex check_mtx_;
void notify_( command);
public:
spin_condition();
void notify_one();
void notify_all();
void wait( unique_lock< spin_mutex > & lk)
{
if ( ! lk)
throw lock_error();
wait( * lk.mutex() );
}
template< typename Pred >
void wait( unique_lock< spin_mutex > & lk, Pred pred)
{
if ( ! lk)
throw lock_error();
while ( ! pred() )
wait( * lk.mutex() );
}
template< typename LockType >
void wait( LockType & lt)
{
{
spin_mutex::scoped_lock lk( enter_mtx_);
BOOST_ASSERT( lk);
waiters_.fetch_add( 1);
lt.unlock();
}
bool unlock_enter_mtx = false;
for (;;)
{
while ( SLEEPING == cmd_.load() )
{
if ( this_tasklet::runs_as_tasklet() )
this_tasklet::yield();
else
this_thread::yield();
}
spin_mutex::scoped_lock lk( check_mtx_);
BOOST_ASSERT( lk);
command expected = NOTIFY_ONE;
cmd_.compare_exchange_strong( expected, SLEEPING);
if ( SLEEPING == expected)
continue;
else if ( NOTIFY_ONE == expected)
{
unlock_enter_mtx = true;
waiters_.fetch_sub( 1);
break;
}
else
{
unlock_enter_mtx = 1 == waiters_.fetch_sub( 1);
if ( unlock_enter_mtx)
{
expected = NOTIFY_ALL;
cmd_.compare_exchange_strong( expected, SLEEPING);
}
break;
}
}
if ( unlock_enter_mtx)
enter_mtx_.unlock();
lt.lock();
}
template<
typename LockType,
typename Pred
>
void wait( LockType & lt, Pred pred)
{
while ( ! pred() )
wait( lt);
}
};
}}
# if defined(BOOST_MSVC)
# pragma warning(pop)
# endif
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_TASKLETS_SPIN_CONDITION_H

View File

@@ -1,66 +0,0 @@
// Copyright Oliver Kowalke 2009.
// 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)
//
// based on boost::interprocess::sync::interprocess_spin_mutex
#ifndef BOOST_TASKLETS_SPIN_MUTEX_H
#define BOOST_TASKLETS_SPIN_MUTEX_H
#include <boost/atomic.hpp>
#include <boost/config.hpp>
#include <boost/thread/locks.hpp>
#include <boost/utility.hpp>
#include <boost/tasklet/detail/config.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
# if defined(BOOST_MSVC)
# pragma warning(push)
# pragma warning(disable:4355 4251 4275)
# endif
namespace boost {
namespace tasklets {
class BOOST_TASKLET_DECL spin_mutex : private noncopyable
{
private:
enum state
{
LOCKED = 0,
UNLOCKED
};
atomic< state > state_;
public:
typedef unique_lock< spin_mutex > scoped_lock;
spin_mutex();
void lock();
bool try_lock();
void unlock();
};
typedef spin_mutex try_spin_mutex;
}}
# if defined(BOOST_MSVC)
# pragma warning(pop)
# endif
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_TASKLETS_SPIN_MUTEX_H

View File

@@ -1,187 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKLETS_STRATEGY_H
#define BOOST_TASKLETS_STRATEGY_H
#include <cstddef>
#include <boost/config.hpp>
#include <boost/move/move.hpp>
#include <boost/tasklet/detail/interrupt_flags.hpp>
#include <boost/tasklet/spin_mutex.hpp>
#include <boost/tasklet/object/id.hpp>
#include <boost/tasklet/tasklet.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
# if defined(BOOST_MSVC)
# pragma warning(push)
# pragma warning(disable:4251)
# endif
namespace boost {
namespace this_tasklet {
bool runs_as_tasklet();
tasklet::id get_id();
void yield();
void cancel();
int priority();
void priority( int);
void interruption_point();
bool interruption_requested();
bool interruption_enabled();
void submit_tasklet( tasklet);
class disable_interruption;
class restore_interruption;
}
namespace tasklets {
class auto_reset_event;
class condition;
class count_down_event;
class manual_reset_event;
class mutex;
class BOOST_TASKLET_DECL strategy
{
private:
friend bool this_tasklet::runs_as_tasklet();
friend tasklet::id this_tasklet::get_id();
friend void this_tasklet::yield();
friend void this_tasklet::cancel();
friend int this_tasklet::priority();
friend void this_tasklet::priority( int);
friend void this_tasklet::interruption_point();
friend bool this_tasklet::interruption_requested();
friend bool this_tasklet::interruption_enabled();
friend void this_tasklet::submit_tasklet( tasklet);
friend class this_tasklet::disable_interruption;
friend class this_tasklet::restore_interruption;
friend class auto_reset_event;
friend class condition;
friend class count_down_event;
friend class manual_reset_event;
friend class mutex;
static bool runs_as_tasklet_();
static tasklet::id get_id_();
static void interruption_point_();
static bool interruption_requested_();
static detail::interrupt_type & interrupt_flags_();
static bool interruption_enabled_();
static int priority_();
static void priority_( int);
static void yield_();
static void cancel_();
static void submit_tasklet_( tasklet);
protected:
static BOOST_TASKLET_TSSDECL tasklet * active_tasklet;
static void call( tasklet &);
static void yield( tasklet &);
static void detach( tasklet &);
static void enable_interruption( tasklet &);
static bool interruption_enabled( tasklet const&);
static bool in_state_not_started( tasklet const&);
static bool in_state_ready( tasklet const&);
static bool in_state_running( tasklet const&);
static bool in_state_wait_for_tasklet( tasklet const&);
static bool in_state_wait_for_object( tasklet const&);
static bool in_state_terminated( tasklet const&);
static void set_state_ready( tasklet &);
static void set_state_running( tasklet &);
static void set_state_wait_for_tasklet( tasklet &);
static void set_state_wait_for_object( tasklet &);
static void set_state_terminated( tasklet &);
void attach( tasklet &);
public:
strategy();
virtual ~strategy();
virtual void add( tasklet &) = 0;
virtual void join( tasklet &) = 0;
virtual void interrupt( tasklet &) = 0;
virtual void reschedule( tasklet &) = 0;
virtual void cancel( tasklet &) = 0;
virtual void yield() = 0;
virtual void wait_for_object( object::id const&, spin_mutex::scoped_lock & lk) = 0;
virtual void object_notify_one( object::id const&) = 0;
virtual void object_notify_all( object::id const&) = 0;
virtual void release( tasklet &) = 0;
virtual void migrate( tasklet &) = 0;
virtual void detach_all() = 0;
virtual bool run() = 0;
virtual bool empty() const = 0;
virtual std::size_t size() const = 0;
virtual std::size_t ready() const = 0;
virtual bool has_ready() const = 0;
};
}}
# if defined(BOOST_MSVC)
# pragma warning(pop)
# endif
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_TASKLETS_STRATEGY_H

View File

@@ -1,226 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKLETS_TASKLET_H
#define BOOST_TASKLETS_TASKLET_H
#include <cstddef>
#include <iostream>
#include <boost/config.hpp>
#include <boost/bind.hpp>
#include <boost/cstdint.hpp>
#include <boost/preprocessor/repetition.hpp>
#include <boost/move/move.hpp>
#include <boost/type_traits/remove_reference.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/utility.hpp>
#include <boost/tasklet/detail/config.hpp>
#include <boost/tasklet/detail/tasklet_base.hpp>
#include <boost/tasklet/detail/tasklet_object.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
# if defined(BOOST_MSVC)
# pragma warning(push)
# pragma warning(disable:4251)
# endif
namespace boost {
namespace tasklets {
class condition;
class mutex;
class strategy;
template< typename Strategy >
class scheduler;
class BOOST_TASKLET_DECL tasklet
{
private:
friend class condition;
friend class mutex;
friend class strategy;
template< typename Strategy >
friend class scheduler;
BOOST_COPYABLE_AND_MOVABLE( tasklet);
detail::tasklet_base::ptr impl_;
template< typename Fn, typename AllocatorT >
static detail::tasklet_base::ptr make_impl_(
Fn fn, std::size_t stacksize, AllocatorT const& alloc)
{
return detail::tasklet_base::ptr(
new detail::tasklet_object< Fn >( fn, stacksize, alloc) );
}
template< typename Fn, typename AllocatorT >
static detail::tasklet_base::ptr make_impl_(
BOOST_RV_REF( Fn) fn, std::size_t stacksize, AllocatorT const& alloc)
{
return detail::tasklet_base::ptr(
new detail::tasklet_object< Fn >( fn, stacksize, alloc) );
}
public:
static std::size_t default_stacksize;
class id;
tasklet();
template< typename Fn, typename AllocatorT >
explicit tasklet( Fn fn, std::size_t stacksize, AllocatorT const& alloc) :
impl_( make_impl_( fn, stacksize, alloc) )
{}
#define BOOST_TASKLET_ARG(z, n, unused) \
BOOST_PP_CAT(A, n) BOOST_PP_CAT(a, n)
#define BOOST_ENUM_TASKLET_ARGS(n) BOOST_PP_ENUM(n, BOOST_TASKLET_ARG, ~)
#define BOOST_TASKLET_TASKLET_CTOR(z, n, unused) \
template< typename Fn, BOOST_PP_ENUM_PARAMS(n, typename A), typename AllocatorT > \
tasklet( Fn fn, BOOST_ENUM_TASKLET_ARGS(n), std::size_t stacksize, AllocatorT const& alloc) : \
impl_( \
make_impl_( \
boost::bind( boost::type< void >(), fn, BOOST_PP_ENUM_PARAMS(n, a) ), \
stacksize, alloc) ) \
{} \
#ifndef BOOST_TASKLET_MAX_ARITY
#define BOOST_TASKLET_MAX_ARITY 10
#endif
BOOST_PP_REPEAT_FROM_TO( 1, BOOST_TASKLET_MAX_ARITY, BOOST_TASKLET_TASKLET_CTOR, ~)
#undef BOOST_TASKLET_TASKLET_CTOR
template< typename Fn, typename AllocatorT >
explicit tasklet( BOOST_RV_REF( Fn) fn, std::size_t stacksize, AllocatorT const& alloc) :
impl_( make_impl_( fn, stacksize, alloc) )
{}
tasklet( tasklet const& other);
tasklet & operator=( BOOST_COPY_ASSIGN_REF( tasklet) other);
tasklet( BOOST_RV_REF( tasklet) other);
tasklet & operator=( BOOST_RV_REF( tasklet) other);
typedef detail::tasklet_base::ptr::unspecified_bool_type unspecified_bool_type;
operator unspecified_bool_type() const;
bool operator!() const;
void swap( tasklet & other);
id get_id() const;
bool operator==( tasklet const& other) const;
bool operator!=( tasklet const& other) const;
bool is_alive() const;
int priority() const;
void priority( int);
void interrupt();
bool interruption_requested() const;
void cancel();
void join();
};
class BOOST_TASKLET_DECL tasklet::id
{
private:
friend class tasklet;
uint64_t id_;
explicit id( detail::tasklet_base::ptr info) :
id_( reinterpret_cast< uint64_t >( info.get() ) )
{}
public:
id() :
id_( 0)
{}
bool operator==( id const& other) const
{ return id_ == other.id_; }
bool operator!=( id const& other) const
{ return id_ != other.id_; }
bool operator<( id const& other) const
{ return id_ < other.id_; }
bool operator>( id const& other) const
{ return other.id_ < id_; }
bool operator<=( id const& other) const
{ return !( other.id_ < id_); }
bool operator>=( id const& other) const
{ return ! ( id_ < other.id_); }
template< typename charT, class traitsT >
friend std::basic_ostream< charT, traitsT > &
operator<<( std::basic_ostream< charT, traitsT > & os, id const& other)
{
if ( 0 != other.id_)
return os << other.id_;
else
return os << "{not-a-tasklet}";
}
};
template< typename Fn >
tasklet make_tasklet( Fn fn, std::size_t stacksize)
{ return tasklet( fn, stacksize); }
#define BOOST_TASKLET_MAKE_TASKLET_FUNCTION(z, n, unused) \
template< typename Fn, BOOST_PP_ENUM_PARAMS(n, typename A) > \
tasklet make_tasklet( Fn fn, BOOST_ENUM_TASKLET_ARGS(n), std::size_t stacksize) \
{ return tasklet( fn, BOOST_PP_ENUM_PARAMS(n, a), stacksize); }
BOOST_PP_REPEAT_FROM_TO( 1, BOOST_TASKLET_MAX_ARITY, BOOST_TASKLET_MAKE_TASKLET_FUNCTION, ~)
#undef BOOST_TASKLET_MAKE_TASKLET_FUNCTION
#undef BOOST_ENUM_TASKLET_ARGS
#undef BOOST_TASKLET_ARG
#undef BOOST_TASKLET_MAX_ARITY
}
using tasklets::tasklet;
inline
void swap( tasklet & l, tasklet & r)
{ return l.swap( r); }
}
# if defined(BOOST_MSVC)
# pragma warning(pop)
# endif
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_TASKLETS_TASKLET_H

View File

@@ -1,197 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_TASKLETS_UNBOUNDED_CHANNEL_H
#define BOOST_TASKLETS_UNBOUNDED_CHANNEL_H
#include <cstddef>
#include <stdexcept>
#include <boost/atomic.hpp>
#include <boost/config.hpp>
#include <boost/intrusive_ptr.hpp>
#include <boost/optional.hpp>
#include <boost/utility.hpp>
#include <boost/tasklet/exceptions.hpp>
#include <boost/tasklet/condition.hpp>
#include <boost/tasklet/mutex.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
namespace boost {
namespace tasklets {
namespace detail {
template< typename T >
struct unbounded_channel_node
{
typedef intrusive_ptr< unbounded_channel_node > ptr;
atomic< std::size_t > use_count;
T va;
ptr next;
unbounded_channel_node() :
use_count( 0),
va(),
next()
{}
};
template< typename T >
void intrusive_ptr_add_ref( unbounded_channel_node< T > * p)
{ p->use_count.fetch_add( 1, memory_order_relaxed); }
template< typename T >
void intrusive_ptr_release( unbounded_channel_node< T > * p)
{
if ( p->use_count.fetch_sub( 1, memory_order_release) == 1)
{
atomic_thread_fence( memory_order_acquire);
delete p;
}
}
}
template< typename T >
class unbounded_channel : private noncopyable
{
public:
typedef optional< T > value_type;
private:
typedef detail::unbounded_channel_node< value_type > node_type;
template< typename X >
friend void intrusive_ptr_add_ref( unbounded_channel< X > * p);
template< typename X >
friend void intrusive_ptr_release( unbounded_channel< X > * p);
enum state
{
ACTIVE = 0,
DEACTIVE
};
atomic< state > state_;
typename node_type::ptr head_;
mutable mutex head_mtx_;
typename node_type::ptr tail_;
mutable mutex tail_mtx_;
condition not_empty_cond_;
atomic< std::size_t > use_count_;
bool active_() const
{ return ACTIVE == state_.load(); }
void deactivate_()
{ state_.store( DEACTIVE); }
bool empty_() const
{ return head_ == get_tail_(); }
typename node_type::ptr get_tail_() const
{
mutex::scoped_lock lk( tail_mtx_);
typename node_type::ptr tmp = tail_;
return tmp;
}
typename node_type::ptr pop_head_()
{
typename node_type::ptr old_head = head_;
head_ = old_head->next;
return old_head;
}
public:
unbounded_channel() :
state_( ACTIVE),
head_( new node_type() ),
head_mtx_(),
tail_( head_),
tail_mtx_(),
not_empty_cond_(),
use_count_( 0)
{}
bool active() const
{ return active_(); }
void deactivate()
{
mutex::scoped_lock lk( head_mtx_);
deactivate_();
not_empty_cond_.notify_all();
}
bool empty() const
{
mutex::scoped_lock lk( head_mtx_);
return empty_();
}
void put( T const& t)
{
typename node_type::ptr new_node( new node_type() );
{
mutex::scoped_lock lk( tail_mtx_);
if ( ! active_() )
throw std::runtime_error("queue is not active");
tail_->va = t;
tail_->next = new_node;
tail_ = new_node;
}
not_empty_cond_.notify_one();
}
bool take( value_type & va)
{
mutex::scoped_lock lk( head_mtx_);
bool empty = empty_();
if ( ! active_() && empty)
return false;
if ( empty)
{
try
{
while ( active_() && empty_() )
not_empty_cond_.wait( lk);
}
catch ( tasklet_interrupted const&)
{ return false; }
}
if ( ! active_() && empty_() )
return false;
swap( va, head_->va);
pop_head_();
return va;
}
bool try_take( value_type & va)
{
mutex::scoped_lock lk( head_mtx_);
if ( empty_() )
return false;
swap( va, head_->va);
pop_head_();
return va;
}
};
}}
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_TASKLETS_UNBOUNDED_CHANNEL_H

View File

@@ -1,71 +0,0 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_THIS_TASKLET_UTILITY_H
#define BOOST_THIS_TASKLET_UTILITY_H
#include <boost/bind.hpp>
#include <boost/config.hpp>
#include <boost/function.hpp>
#include <boost/move/move.hpp>
#include <boost/tasklet/tasklet.hpp>
#include <boost/tasklet/strategy.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
namespace boost {
namespace this_tasklet {
inline
bool runs_as_tasklet()
{ return tasklets::strategy::runs_as_tasklet_(); }
inline
tasklet::id get_id()
{ return tasklets::strategy::get_id_(); }
inline
int priority()
{ return tasklets::strategy::priority_(); }
inline
void priority( int prio)
{ tasklets::strategy::priority_( prio); }
inline
void interruption_point()
{ tasklets::strategy::interruption_point_(); }
inline
bool interruption_requested()
{ return tasklets::strategy::interruption_requested_(); }
inline
bool interruption_enabled()
{ return tasklets::strategy::interruption_enabled_(); }
inline
void yield()
{ tasklets::strategy::yield_(); }
inline
void cancel()
{ tasklets::strategy::cancel_(); }
inline
void submit_tasklet( tasklet f)
{ tasklets::strategy::submit_tasklet_( f); }
}}
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_THIS_TASKLET_UTILITY_H

View File

@@ -1,89 +0,0 @@
# Boost.Task Library Build Jamfile
# Copyright Oliver Kowalke 2009.
# 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)
import os ;
import feature ;
import indirect ;
import path ;
project boost/task
: source-location
../src
: requirements
<library>/boost/tasklet//boost_tasklet
<library>/boost/thread//boost_thread
<library>/boost/system//boost_system
<link>static:<define>BOOST_TASKS_BUILD_LIB=1
<link>shared:<define>BOOST_TASKS_BUILD_DLL=1
<threading>multi
: default-build
<threading>multi
;
local rule default_taskapi ( )
{
local api = posix ;
if [ os.name ] = "NT" { api = win32 ; }
return $(api) ;
}
feature.feature taskapi : posix win32 : propagated ;
feature.set-default taskapi : [ default_taskapi ] ;
alias task_sources
: ## win32 sources ##
callable.cpp
context.cpp
fast_semaphore.cpp
poolsize.cpp
semaphore_windows.cpp
spin/auto_reset_event.cpp
spin/barrier.cpp
spin/condition.cpp
spin/count_down_event.cpp
spin/manual_reset_event.cpp
spin/mutex.cpp
stacksize.cpp
watermark.cpp
detail/worker.cpp
detail/worker_group.cpp
detail/wsq.cpp
: ## requirements ##
<taskapi>win32
;
alias task_sources
: ## posix sources ##
callable.cpp
context.cpp
fast_semaphore.cpp
poolsize.cpp
semaphore_posix.cpp
spin/auto_reset_event.cpp
spin/barrier.cpp
spin/condition.cpp
spin/count_down_event.cpp
spin/manual_reset_event.cpp
spin/mutex.cpp
stacksize.cpp
watermark.cpp
detail/worker.cpp
detail/worker_group.cpp
detail/wsq.cpp
: ## requirements ##
<taskapi>posix
;
explicit task_sources ;
lib boost_task
: task_sources
: <link>shared:<define>BOOST_TASKS_USE_DLL=1
<link>static:<define>BOOST_TASKS_USE_LIB=1
;
boost-install boost_task ;

View File

@@ -1,36 +0,0 @@
# Boost.ThreadPool Library Documentation Jamfile
# Copyright (C) 2008 Oliver Kowalke
# Use, modification and distribution is subject to the Boost Software License,
# Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
path-constant boost-images : ../../../doc/src/images ;
xml task : task.qbk ;
boostbook standalone
:
task
:
# HTML options first:
# Use graphics not text for navigation:
<xsl:param>navig.graphics=1
# How far down we chunk nested sections, basically all of them:
<xsl:param>chunk.section.depth=3
# Don't put the first section on the same page as the TOC:
<xsl:param>chunk.first.sections=1
# How far down sections get TOC's
<xsl:param>toc.section.depth=10
# Max depth in each TOC:
<xsl:param>toc.max.depth=3
# How far down we go with TOC's
<xsl:param>generate.section.toc.level=10
# Path for links to Boost:
<xsl:param>boost.root=../../../..
# Path for libraries index:
<xsl:param>boost.libraries=../../../../libs/libraries.htm
# Use the main Boost stylesheet:
<xsl:param>html.stylesheet=../../../../doc/html/boostbook.css
;

View File

@@ -1,13 +0,0 @@
[/
Copyright Oliver Kowalke 2009.
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:acknowledgements Acknowledgments]
I'd like to thank Vicente J. Botet Escriba for his comments.
[endsect]

View File

@@ -1,40 +0,0 @@
[/
Copyright Oliver Kowalke 2009.
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:as_sub_task Execute as Sub-Task]
__as_sub_task__ is a convenient way to execute a __sub_task__. If the parent task is executed inside a __thread_pool__ the __sub_task__ is put into the local-queue of the
__worker_thread__ in the other case the __sub_task__ will be executed in a new thread. __as_sub_task__ is used as default __ep__ for __fn_async__,
boost::task::handle< long > h(
boost::task::async(
boost::task::make_task( fibonacci, 10),
boost::task::as_sub_task() ) );
[section:as_sub_task Class `as_sub_task`]
#include <boost/task/as_sub_task.hpp>
struct as_sub_task
{
template< typename R >
handle< R > operator()( task< R >);
};
[section `template< typename R > handle< R > operator()( task< R > t)`]
[variablelist
[[Effects:] [moves task in a new thread or thread-pool and returns an handle associated with the task]]
[[Throws:] [`boost::thread_resource_error`]]
]
[endsect]
[endsect]
[endsect]

View File

@@ -1,315 +0,0 @@
[/
Copyright Oliver Kowalke 2009.
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:async_completion_token Asynchronous Completion Token]
[heading Synopsis]
The __act__ dispatches processing tasks in response to the completion of asynchronous operations. __act__ uniquely identifies
the task and state necessary to process the result of the operation [footnote see [@http://www.cs.wustl.edu/~schmidt/PDF/ACT.pdf 'Asynchronous Completion Token'], Douglas Schmidt].
__handle__ represents an __act__. It will be returned by __async__ and is associated with the submitted __task__.
long fibonacci( 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()
{
// create task
boost::tasks::task< long > t( fibonacci, 10);
// move task ownership to executor
boost::tasks::handle< long > h(
boost::tasks::async(
boost::move( t),
boost::tasks::new_thread() ) );
std::cout << "is ready == " << std::boolalpha << h.is_ready() << "\n";
// wait for task completion
h.wait();
std::cout << "has value == " << std::boolalpha << h.has_value() << "\n";
std::cout << "has exception == " << std::boolalpha << h.has_exception() << "\n";
// return result
std::cout << "fibonacci(10) == " << h.get() << std::endl;
}
[heading Interruption]
Each invokation of __fn_async__ returns an __handle__ which allows to control the associated __task__ (passed to __fn_async__). This includes
the ability to interrupt an __task__ if it is cooperative. Cooperative means that the __task__ contains __interruption_points__ or checks for
interruption requests [footnote see [@http://www.ddj.com/architect/207100682 'Interrupt Politely'], Herb Sutter].
* __fn_interrupt__: interrupt __task__ and return immediately
* __fn_interrupt_and_wait__: interrupt and wait until __task__ was removed from __worker_thread__
* __fn_interrupt_and_wait_for__: interrupt and wait until __task__ was removed from __worker_thread__ or time duration has elapsed
* __fn_interrupt_and_wait_until__: interrupt and wait until __task__ was removed from __worker_thread__ or time point has reached
* __fn_interruption_requested__: return bool if interruption was requested
long cooperative( long n)
{
boost::this_thread::interruption_point(); // interruption point
if ( n == 0) return 0;
if ( n == 1) return 1;
long k1( 1), k2( 0);
for ( int i( 2); i <= n; ++i)
{
if ( boost::this_thread::interruption_requested() ) // check if interruption was requested
return;
long tmp( k1);
k1 = k1 + k2;
k2 = tmp;
}
boost::this_thread::interruption_point(); // interruption point
return k1;
}
void main()
{
// task, to be executed asynchronously
boost::tasks::task< long > t( cooperative, 10);
// move task to async. executor
boost::tasks::handle< long > h(
boost::tasks::async(
boost::move( t),
boost::tasks::new_thread() ) );
// interrupt task and wait until task is removed by worker-thread
h.interrupt_and_wait();
std::cout << "is ready == " << std::boolalpha << h.is_ready() << "\n";
std::cout << "has value == " << std::boolalpha << h.has_value() << "\n";
std::cout << "has exception == " << std::boolalpha << h.has_exception() << "\n";
// access result
// throws boost::tasks::task_interrupted
std::cout << h.get() << std::endl;
}
[note If the task is still pending (not executed yet) when an interruption is requested - the task is not removed from the queue, it is marked to be interrupted instead.]
[heading Completion]
__boost_task__ provides function __waitfor_all__ waits for all handles passed to this function to become ready
void main()
{
std::vector handles< boost::tasks::handle< long > > results;
results.reserve( 10);
for ( int i = 0; i < 10; ++i)
{
boost::tasks::task< long > t( fibonacci, i);
results.push_back(
boost::tasks::async(
boost::move( t) ) );
}
// wait until all tasks are ready
boost::tasks::waitfor_all( results.begin(), results.end() );
int k = 0;
std::vector< boost::tasks::handle< long > >::iterator e( results.end() );
for (
std::vector< boost::tasks::handle< long > >::iterator i( results.begin() );
i != e;
++i)
std::cout << "fibonacci(" << k++ << ") == " << i->get() << std::endl;
}
[section:handle Class template `handle`]
#include <boost/task/handle.hpp>
template< typename R >
class handle
{
handle();
template< typename F >
handle( F const&, context const&);
void interrupt();
void interrupt_and_wait();
void interrupt_and_wait_until( system_time const& abs_time);
template< typename TimeDuration >
void interrupt_and_wait_for( Duration const& rel_time);
bool interruption_requested();
R get();
bool is_ready() const;
bool has_value() const;
bool has_exception() const;
void wait() const;
bool wait_until( system_time const& abs_time);
template< typename TimeDuration >
bool wait_for( TimeDuration const& rel_time);
void swap( handle< R > & other);
};
template< typename Iterator >
friend void waitfor_all( Iterator begin, Iterator end);
template< typename T1, typename T2 >
friend void waitfor_all( T1 & t1, T2 & t2);
...
template< typename T1, typename T2, typename T3, typename T4, typename T5 >
friend void waitfor_all( handle< T1 > & t1, handle< T2 > & t2, handle< T3 > & t3, handle< T4 > & t4, handle< T5 > & t5);
[section `handle()`]
[variablelist
[[Effects:] [constructs an empty (invalid) handle]]
[[Throws:] [Nothing]]
]
[endsect]
[section `template< typename F > handle( F const&, context const&)`]
[variablelist
[[Effects:] [constructs an handle associated with an future and an context]]
[[Throws:] [Nothing]]
]
[endsect]
[section `bool interruption_requested()`]
[variablelist
[[Effects:] [checks if interruption is already requested]]
[[Throws:] [Nothing]]
]
[endsect]
[section `void interrupt()`]
[variablelist
[[Effects:] [requests task interruption; doesn not block (immediatly returns)]]
[[Throws:] [Nothing]]
]
[endsect]
[section `void interrupt_and_wait()`]
[variablelist
[[Effects:] [requests task interruption and blocks until worker-thread stops task]]
[[Throws:] [`boost::thread_resource_error`]]
]
[endsect]
[section `bool interrupt_and_wait_until( system_time const&)`]
[variablelist
[[Effects:] [requests task interruption and blocks until worker-thread stops task or time-point elapsed]]
[[Returns:] [false if the the time specified by abs_time was reached, true otherwise]]
[[Throws:] [`boost::thread_resource_error`]]
]
[endsect]
[section `template< typename TimeDuration > interrupt_and_wait_for( TimeDuration const&)`]
[variablelist
[[Effects:] [requests task interruption and blocks until worker-thread stops task or time-duration elapsed]]
[[Returns:] [false if the the time specified by rel_time was reached, true otherwise]]
[[Throws:] [`boost::thread_resource_error`]]
]
[endsect]
[section `R get()`]
[variablelist
[[Effects:] [requests the result]]
[[Throws:] [`boost::task::task_interrupted`, `boost::task::task_uninialized`, `boost::task::task_rejected`, `boost::task::broken_task`]]
]
[endsect]
[section `void wait()`]
[variablelist
[[Effects:] [blocks caller until task is done]]
[[Throws:] [`boost::task::task_interrupted`, `boost::task::task_uninialized`, `boost::task::task_rejected`, `boost::task::broken_task`]]
]
[endsect]
[section `template< typename TimeDuration > wait_for( TimeDuration const&)`]
[variablelist
[[Effects:] [blocks caller until task is done]]
[[Throws:] [`boost::task::task_interrupted`, `boost::task::task_uninialized`, `boost::task::task_rejected`, `boost::task::broken_task`]]
]
[endsect]
[section `bool wait_until( system_time const& abs_time) const`]
[variablelist
[[Effects:] [blocks caller until task is done]]
[[Throws:] [`boost::task::task_interrupted`, `boost::task::task_uninialized`, `boost::task::task_rejected`, `boost::task::broken_task`]]
]
[endsect]
[section `bool is_ready()`]
[variablelist
[[Effects:] [checks if task is done]]
[[Throws:] [Nothing]]
]
[endsect]
[section `bool has_value()`]
[variablelist
[[Effects:] [checks if task is done and a result value is set]]
[[Throws:] [Nothing]]
]
[endsect]
[section `bool has_exception()`]
[variablelist
[[Effects:] [checks if task is done and an exception is set]]
[[Throws:] [Nothing]]
]
[endsect]
[section `void swap( handle< R > & other)`]
[variablelist
[[Effects:] [swapps handle]]
[[Throws:] [Nothing]]
]
[endsect]
[section Non-member function `wait_for_all()`]
template< typename Iterator >
void waitfor_all( Iterator begin, Iterator end);
template< typename T1, typename T2 >
void waitfor_all( T1 & t1, T2 & t2);
...
template< typename T1, typename T2, typename T3, typename T4, typename T5 >
void waitfor_all( handle< T1 > & t1, handle< T2 > & t2, handle< T3 > & t3, handle< T4 > & t4, handle< T5 > & t5);
[variablelist
[[Effects:] [waits for all handles to become ready]]
[[Throws:] [`boost::task::task_interrupted`, `boost::task::task_rejected`]]
]
[endsect]
[endsect]
[endsect]

View File

@@ -1,90 +0,0 @@
[/ Copyright Oliver Kowalke 2009.
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:async_execution Asynchronous Execution]
[heading Synopsis]
In order to execute a task it has to be passed to function __fn_async__. The task is store inside
the __ep__ (may be given as an additional argument to __fn_async__) and will by means of __ep__.
[section:async Non-member function `async()`]
Function __fn_async__ applies the moved __task__ to the __ep__ which executes the __task__ (for this purpose __ep__ is
required to provide `handle< R > operator()( task< R > && t)`).
The function returns a __handle__ which controls the submitted __task__.
long fibonacci( 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()
{
// task computing fibonacci(10)
// move the task to executor
boost::tasks::handle< long > h1(
boost::tasks::async(
boost::tasks::make_task( fibonacci, 10) ) );
// task computing fibonacci(5)
boost::task< long > t( fibonacci, 5);
// move the task to executor
boost::tasks::handle< long > h2(
boost::tasks::async(
boost::move( t) ) );
// access the results
std::cout << "fibonacci(10) == " << h1.get() << std::endl;
std::cout << "fibonacci(5) == " << h2.get() << std::endl;
}
[section:async Non-member function `async()`]
#include <boost/task/async.hpp>
template< typename R >
handle< R > async( task< R > t);
template< typename R >
handle< R > async( task< R > t, own_thread ep);
template< typename R >
handle< R > async( task< R > t, new_thread ep);
template< typename R, typename Channel >
handle< R > async( task< R > t, pool< Channel > & ep);
template< typename R, typename Channel, typename Attr >
handle< R > async( task< R > t, Attr attr, pool< Channel > & ep);
template< typename R, typename Strategy >
handle< R > async( task< R > t, tasklets::scheduler< Strategy > & ep);
[variablelist
[[Effects:] [moves task to an asyncrounous executer and returns a handle associated with the task]]
[[Throws:] [`boost::thread_resource_error`]]
]
[endsect]
[endsect]
[include async_completion_token.qbk]
[include execution_policies.qbk]
[endsect]

View File

@@ -1,21 +0,0 @@
[/
Copyright Oliver Kowalke 2009.
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:execution_policy Execution Policies]
In contrast to synchronous methods asynchronous methods do not block the program flow when a time consuming operation is executed.
The application continues executing the current context and when the result of the asynchronous method is required the __act__ can be used.
A __ep__ describes how a __task__ gets asynchronously executed and provides a __act__ to manage the __task__.
[include own_thread.qbk]
[include new_thread.qbk]
[include as_sub_task.qbk]
[include threadpool.qbk]
[endsect]

View File

@@ -1,78 +0,0 @@
/
Copyright Oliver Kowalke 2009.
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:forkjoin Fork/Join]
Fork/Join algorithms are recursive divide-and-conquer algorithms which repeatedly splitt into sub-tasks 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 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__.
``
long serial_fib( long n)
{
if( n < 2) return n;
else return serial_fib( n - 1) + serial_fib( n - 2);
}
long parallel_fib( long n, long cutof)
{
if ( n < cutof) return serial_fib( n);
else
{
// fork sub-task by moving the task
// ownership to the thread-pool
// sub-task computes fibonacci(n-1)
h1 = boost::task::async(
boost::task::make_task(
parallel_fib,
n - 1,
cutof) );
// fork sub-task by moving the task
// ownership to the thread-pool
// sub-task computes fibonacci(n-2)
h2 = boost::task::async(
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();
}
}
void main()
{
boost::task::static_pool< boost::task::unbounded_fifo > pool( boost::task::poolsize( 5) );
// compute fibonacci-number 10
// for numbers < 5 do inline calculation
boost::task::task< long > t(
parallel_fib,
10,
5);
// move task ownership to thread-pool
boost::task::handle< long > h(
boost::task::async(
boost::move( t),
pool) );
// access result
std::cout << "fibonacci(10) == " << h.get() << std::endl;
}
``
[endsect]

View File

@@ -1,333 +0,0 @@
[/
Copyright Oliver Kowalke 2009.
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:handle Class template `handle`]
[heading Synopsis]
__handle__ represents an __act__. It will be returned by __async__ and is associated with the submitted __task__.
long fibonacci( 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()
{
// create task
boost::tasks::task< long > t( fibonacci, 10);
// move task ownership to executor
boost::tasks::handle< long > h(
boost::tasks::async(
boost::move( t),
boost::tasks::new_thread() ) );
std::cout << "is ready == " << std::boolalpha << h.is_ready() << "\n";
// wait for task completion
h.wait();
std::cout << "has value == " << std::boolalpha << h.has_value() << "\n";
std::cout << "has exception == " << std::boolalpha << h.has_exception() << "\n";
// return result
std::cout << "fibonacci(10) == " << h.get() << std::endl;
}
[heading Interruption]
Each invokation of __fn_async__ returns an __handle__ which allows to control the associated __task__ (passed to __fn_async__). This includes
the ability to interrupt an __task__ if it is cooperative. Cooperative means that the __task__ contains __interruption_points__ or checks for
interruption requests [footnote see [@http://www.ddj.com/architect/207100682 'Interrupt Politely'], Herb Sutter].
* __fn_interrupt__: interrupt __task__ and return immediately
* __fn_interrupt_and_wait__: interrupt and wait until __task__ was removed from __worker_thread__
* __fn_interrupt_and_wait_for__: interrupt and wait until __task__ was removed from __worker_thread__ or time duration has elapsed
* __fn_interrupt_and_wait_until__: interrupt and wait until __task__ was removed from __worker_thread__ or time point has reached
* __fn_interruption_requested__: return bool if interruption was requested
long cooperative( long n)
{
boost::this_thread::interruption_point(); // interruption point
if ( n == 0) return 0;
if ( n == 1) return 1;
long k1( 1), k2( 0);
for ( int i( 2); i <= n; ++i)
{
if ( boost::this_thread::interruption_requested() ) // check if interruption was requested
return;
long tmp( k1);
k1 = k1 + k2;
k2 = tmp;
}
boost::this_thread::interruption_point(); // interruption point
return k1;
}
void main()
{
// task, to be executed asynchronously
boost::tasks::task< long > t( cooperative, 10);
// move task to async. executor
boost::tasks::handle< long > h(
boost::tasks::async(
boost::move( t),
boost::tasks::new_thread() ) );
// interrupt task and wait until task is removed by worker-thread
h.interrupt_and_wait();
std::cout << "is ready == " << std::boolalpha << h.is_ready() << "\n";
std::cout << "has value == " << std::boolalpha << h.has_value() << "\n";
std::cout << "has exception == " << std::boolalpha << h.has_exception() << "\n";
// access result
// throws boost::tasks::task_interrupted
std::cout << h.get() << std::endl;
}
[note If the task is still pending (not executed yet) when an interruption is requested - the task is not removed from the queue, it is marked to be interrupted instead.]
[heading Completion]
__boost_task__ provides function __waitfor_all__ waits for all handles passed to this function to become ready
void main()
{
std::vector handles< boost::tasks::handle< long > > results;
results.reserve( 10);
for ( int i = 0; i < 10; ++i)
{
boost::tasks::task< long > t( fibonacci, i);
results.push_back(
boost::tasks::async(
boost::move( t) ) );
}
// wait until all tasks are ready
boost::tasks::waitfor_all( results.begin(), results.end() );
int k = 0;
std::vector< boost::tasks::handle< long > >::iterator e( results.end() );
for (
std::vector< boost::tasks::handle< long > >::iterator i( results.begin() );
i != e;
++i)
std::cout << "fibonacci(" << k++ << ") == " << i->get() << std::endl;
}
[section:handle Class template `handle`]
#include <boost/task/handle.hpp>
template< typename R >
class handle
{
handle();
template< typename F >
handle( F const&, context const&);
void interrupt();
void interrupt_and_wait();
void interrupt_and_wait_until( system_time const& abs_time);
template< typename TimeDuration >
void interrupt_and_wait_for( Duration const& rel_time);
bool interruption_requested();
R get();
bool is_ready() const;
bool has_value() const;
bool has_exception() const;
void wait() const;
bool wait_until( system_time const& abs_time);
template< typename TimeDuration >
bool wait_for( TimeDuration const& rel_time);
void swap( handle< R > & other);
};
template< typename Iterator >
friend void waitfor_all( Iterator begin, Iterator end);
template< typename T1, typename T2 >
friend void waitfor_all( T1 & t1, T2 & t2);
...
template< typename T1, typename T2, typename T3, typename T4, typename T5 >
friend void waitfor_all( handle< T1 > & t1, handle< T2 > & t2, handle< T3 > & t3, handle< T4 > & t4, handle< T5 > & t5);
[section `handle()`]
[variablelist
[[Effects:] [constructs an empty (invalid) handle]]
[[Throws:] [Nothing]]
]
[endsect]
[section `template< typename F > handle( F const&, context const&)`]
[variablelist
[[Effects:] [constructs an handle associated with an future and an context]]
[[Throws:] [Nothing]]
]
[endsect]
[section `bool interruption_requested()`]
[variablelist
[[Effects:] [checks if interruption is already requested]]
[[Throws:] [Nothing]]
]
[endsect]
[section `void interrupt()`]
[variablelist
[[Effects:] [requests task interruption; doesn not block (immediatly returns)]]
[[Throws:] [Nothing]]
]
[endsect]
[section `void interrupt_and_wait()`]
[variablelist
[[Effects:] [requests task interruption and blocks until worker-thread stops task]]
[[Throws:] [`boost::thread_resource_error`]]
]
[endsect]
[section `bool interrupt_and_wait_until( system_time const&)`]
[variablelist
[[Effects:] [requests task interruption and blocks until worker-thread stops task or time-point elapsed]]
[[Returns:] [false if the the time specified by abs_time was reached, true otherwise]]
[[Throws:] [`boost::thread_resource_error`]]
]
[endsect]
[section `template< typename TimeDuration > interrupt_and_wait_for( TimeDuration const&)`]
[variablelist
[[Effects:] [requests task interruption and blocks until worker-thread stops task or time-duration elapsed]]
[[Returns:] [false if the the time specified by rel_time was reached, true otherwise]]
[[Throws:] [`boost::thread_resource_error`]]
]
[endsect]
[section `R get()`]
[variablelist
[[Effects:] [requests the result]]
[[Throws:] [`boost::task::task_interrupted`, `boost::task::task_uninialized`, `boost::task::task_rejected`, `boost::task::broken_task`]]
]
[endsect]
[section `void wait()`]
[variablelist
[[Effects:] [blocks caller until task is done]]
[[Throws:] [`boost::task::task_interrupted`, `boost::task::task_uninialized`, `boost::task::task_rejected`, `boost::task::broken_task`]]
]
[endsect]
[section `template< typename TimeDuration > wait_for( TimeDuration const&)`]
[variablelist
[[Effects:] [blocks caller until task is done]]
[[Throws:] [`boost::task::task_interrupted`, `boost::task::task_uninialized`, `boost::task::task_rejected`, `boost::task::broken_task`]]
]
[endsect]
[section `bool wait_until( system_time const& abs_time) const`]
[variablelist
[[Effects:] [blocks caller until task is done]]
[[Throws:] [`boost::task::task_interrupted`, `boost::task::task_uninialized`, `boost::task::task_rejected`, `boost::task::broken_task`]]
]
[endsect]
[section `bool is_ready()`]
[variablelist
[[Effects:] [checks if task is done]]
[[Throws:] [Nothing]]
]
[endsect]
[heading Member function `has_value()`]
bool has_value()
[variablelist
[[Effects:] [checks if task is done and a result value is set]]
[[Throws:] [Nothing]]
]
[heading Member function `has_exception()`]
bool has_exception()
[variablelist
[[Effects:] [checks if task is done and an exception is set]]
[[Throws:] [Nothing]]
]
[heading Member function `get_future()`]
shared_future< R > & get_future()
[variablelist
[[Effects:] [returns a reference to the internal shared_future< R >]]
[[Throws:] [Nothing]]
]
[heading Member function `swap()`]
void swap( handle< R > & other)
[variablelist
[[Effects:] [swapps handle]]
[[Throws:] [Nothing]]
]
[section Non-member function `wait_for_all()`]
template< typename Iterator >
void waitfor_all( Iterator begin, Iterator end);
template< typename T1, typename T2 >
void waitfor_all( T1 & t1, T2 & t2);
...
template< typename T1, typename T2, typename T3, typename T4, typename T5 >
void waitfor_all( handle< T1 > & t1, handle< T2 > & t2, handle< T3 > & t3, handle< T4 > & t4, handle< T5 > & t5);
[variablelist
[[Effects:] [waits for all handles to become ready]]
[[Throws:] [`boost::task::task_interrupted`, `boost::task::task_rejected`]]
]
[endsect]
[endsect]
[endsect]

View File

@@ -1,60 +0,0 @@
[/
Copyright Oliver Kowalke 2009.
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:meta_functions Meta functions]
If the __thread_pool__ supports attributes (like priorities) __has_attribute__ evaluates to `true` at compile-time (derived from
boost::mpl::bool_). The type of the attribute is determined by __attribute_type__.
// thread-pool with priority scheduling
// type of priority is int
typdef boost::task::static_pool< boost::task::unbounded_priority< int > > pool_type;
// test if thread-pool supports priorities at compile time
std::cout << std::boolalpha << boost::task::has_attribute< pool_type >::value << "\n";
// access the type used for priority
std::cout << typeid( boost::task::attribute_type< pool_type >::type).name() << std::endl;
[section:has_attribute Meta function `has_attribute`]
#include <boost/task/meta.hpp>
template< typename Pool >
struct has_attribute : public mpl::bool_<
is_same<
detail::has_priority,
typename Pool::scheduler_type::priority_tag_type
>::value
>
{};
[variablelist
[[Effects:] [returns true if Pool supports attributes (priority-scheduling)]]
[[Throws:] [nothing]]
]
[endsect]
[section:attribute_type Meta function `attribute_type`]
#include <boost/task/meta.hpp>
template< typename Pool >
struct attribute_type
{
typedef typename Pool::scheduler_type::attribute_type type;
};
[variablelist
[[Effects:] [returns type of attribute]]
[[Throws:] [nothing]]
]
[endsect]
[endsect]

View File

@@ -1,86 +0,0 @@
[/
Copyright Oliver Kowalke 2009.
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:new_thread Execute in Separat Thread]
[heading Synopsis]
__new_thread__ creates a new thread and executes the task in this thread (asynchronous). The created thread gets
joined by handle.
The returned __handle__ joins the thread in its destructor (if the last reference gets out of scope).
long fibonacci( 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()
{
boost::task::task< long > t( fibonacci, 10);
boost::task::handle< long > h(
boost::task::async(
boost::move( t),
boost::task::new_thread() ) );
std::cout << "fibonacci(10) == " << h.get() << std::endl;
}
[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). ]
In the example below both `a_function()` and `another_function()` are executed synchron because the returned __handle__ is not stored in
a variable. Thatswhy the __worker_thread__ is joined after return from __fn_async__!
boost::task::task< void > t1( a_function);
boost::task::task< void > t2( another_function);
// handles are not retrieved
// both task executed in sequence
boost::task::async(
boost::move( t1),
boost::task::new_thread() ) );
boost::task::async(
boost::move( t2),
boost::task::new_thread() ) );
[section:new_thread Class `new_thread`]
#include <boost/task/async.hpp>
struct new_thread
{
template< typename R >
handle< R > operator()( task< R >);
};
[section `template< typename R > handle< R > operator()( task< R > t)`]
[variablelist
[[Effects:] [moves task in a new thread an returns an handle associated with the task]]
[[Throws:] [`boost::thread_resource_error`]]
]
[endsect]
[endsect]
[endsect]

View File

@@ -1,140 +0,0 @@
[/
Copyright Oliver Kowalke 2009.
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:overview Overview]
__boost_task__ provides a framework for asynchronous execution of tasks (small units of code that can be executed independently and parallel).
* __task__, a __callable__ representing a fine-grained __work_item__:
* support of task synchron. via primitives like conditions, barriers, event-variables and channels (message exchange)
without blocking worker-thread in the __thread_pool__
* __handle__, works as a __act__ associated with a task:
* __fn_interrupt__, __fn_interrupt_and_wait__, ... allow to cancel an cooperative task
* __fn_get__ retrieve value or exception of task execution
* __fn_is_ready__ test if task was executed
* __fn_wait__, __fn_wait_for__ and __fn_wait_until__ block until task is executed and the result is set
* functions __waitfor_all__ to wait for all handles
* __async__, executes a task by means of __eps__
* executes task in current thread
* executes task in a newly created thread (thread will be destroyed after completion)
* task gets executed by a __worker_thread__ of a custom __thread_pool__ (for instance with priority or smart scheduling)
* executes task in newly created thread or in a pool of __worker_threads__ depending on whether the parent-task is already executed in a __thread_pool__
* __thread_pools__ with __work_stealing__ algorithm and __fork_join__ semantics
In order to use the classes and functions described here, you can either include the specific headers specified by the descriptions of each class or function,
or include the master library header:
#include <boost/task.hpp>
which includes all the other headers in turn.
Used namespaces are:
namespace boost::tasks
namespace boost::this_task
[heading Example]
long fibonacci( 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()
{
// create a thread-pool
boost::tasks::static_pool< boost::tasks::unbounded_fifo > > pool( boost::tasks::poolsize( 5) );
// execute tasks in thread-pool
// move tasks ownership to executor
boost::tasks::handle< long > h1(
boost::tasks::async(
boost::tasks::make_task( fibonacci, 10),
pool);
boost::tasks::handle< long > h2(
boost::tasks::async(
boost::tasks::make_task( fibonacci, 5),
boost::move( t2),
pool);
std::cout << "h1: is ready == " << std::boolalpha << h1.is_ready() << "\n";
std::cout << "h2: is ready == " << std::boolalpha << h2.is_ready() << "\n";
// wait for completion of both tasks
boost::tasks::waitfor_all( h1, h2);
std::cout << "h1: is ready == " << std::boolalpha << h1.is_ready() << "\n";
std::cout << "h2: is ready == " << std::boolalpha << h2.is_ready() << "\n";
std::cout << "h1: has value == " << std::boolalpha << h1.has_value() << "\n";
std::cout << "h2: has value == " << std::boolalpha << h2.has_value() << "\n";
std::cout << "h1: has exception == " << std::boolalpha << h1.has_exception() << "\n";
std::cout << "h2: has exception == " << std::boolalpha << h2.has_exception() << "\n";
// get results
std::cout << "fibonacci(10) == " << h1.get() << std::endl;
std::cout << "fibonacci(5) == " << h2.get() << std::endl;
}
[heading References]
* [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2185.html N2185]: Proposed Text for Parallel Task Execution, written by Peter Dimov.
* [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2276.html N2276]: Thread Pools and Futures, written by Anthony Williams.
* [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2802.html N2802]: A plea to reconsider detach-on-destruction for thread objects, written by Hans-J. Boehm.
* [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2880.html N2880]: C++ object lifetime interactions with the threads API, written by Hans-J. Boehm and Lawrence Crowl.
* [@http://herbsutter.wordpress.com 'Sutters Mill'] by Herb Sutter
* mailing list of C++ standard committee's Library Working Group
[warning This library is NOT an official Boost library]
[note Please note that __boost_task__ is not optimized yet.]
[note __boost_tasklet__ requires [*Boost Library 1.41.0] .]
__boost_task__ depends uppon __boost_atomic__, __boost_move__ and __boost_tasklet__.
[heading Tested Platforms]
__boost_task__ has been tested on the following platforms and compilers:
* Debian GNU/Linux 2.6.31.6 (x86_64), GCC 4.3.4
* Ubuntu GNU/Linux 2.6.28.11 (x86), ICC 11.1
* FreeBSD 8.0 (x86), GCC 4.2.1
* OpenSolaris 2009.06 (x86_64), GCC 4.3.2
* Windows XP Professional (x86), MSVC 9.0
[heading How to build and install]
* download the sources from
[@http://www.boost-consulting.com/vault/index.php?directory=Concurrent%20Programming Boost Vault]
* extract the archive into the boost-source directory
* call [''bjam toolset=<compiler-name> --with-task install'] in order to build and install the library
[endsect]

View File

@@ -1,62 +0,0 @@
[/
Copyright Oliver Kowalke 2009.
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:own_thread Execute in Current Thread]
[heading Synopsis]
__own_thread__ executes the task in the current thread (synchronous execution).
long fibonacci( 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()
{
boost::task::task< long > t( fibonacci, 10);
boost::task::handle< long > h(
boost::task::async(
boost::move( t),
boost::task::own_thread() ) );
std::cout << "fibonacci(10) == " << h.get() << std::endl;
}
[section:own_thread Class `own_thread`]
#include <boost/task/async.hpp>
struct own_thread
{
template< typename R >
handle< R > operator()( task< R > t);
};
[section `template< typename R > handle< R > operator()( task< R > t)`]
[variablelist
[[Effects:] [moves task in the current thread an returns an handle associated with the task]]
[[Throws:] [Nothing]]
]
[endsect]
[endsect]
[endsect]

View File

@@ -1,30 +0,0 @@
[/
Copyright Oliver Kowalke 2009.
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:processor_binding Processor binding]
For some applications it is convenient to bind the __worker_threads__ to processors/cores of the system. For this purpose __fn_bind_to_processors__ must
be given to constructor instead __pool_size__ so that a __worker_thread__ is created an bound the the core.
``
typedef boost::task::static_pool<
boost::task::unbounded_queue< boost::tp::fifo >
> pool_type;
// constructs thread-pool with worker-threads as
// CPUs/Cores are available on the system
pool_type pool( pool_type::bind_to_processors() );
``
The constructor takes additional arguments for the [link_work_stealing work-stealing algorithm] and [link_queue high-] and [link_queue low-watermark] too.
[note __boost_task__ does provide this feature only for Windows, Linux, AIX, HP-UX, Solaris and FreeBSD.]
[endsect]

View File

@@ -1,118 +0,0 @@
[/
Copyright Oliver Kowalke 2009.
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:queue Global Queue]
A __queue__ synchronizes the access between application threads and __worker_threads__ and implements policies for limitating the amount of queued tasks and how those tasks are scheduled ( first-in-first-out, priority ordering etc.)
[heading Bounded Queues]
__bounded_queue__ limits the number of queued (pending) tasks in order to prevent resource exhaustion.
For this purpose a high- and low-watermark has to be passed at construction.
__hwm__ sets the maximum of pending tasks. If this limited is reached all threads which submit a task will be set to sleep (blocked). If it is equal to __lwm__ everytime a
sleeping producer thread will be woken up and puts its task if one worker thread has taken a task from the queue.
__lwm__ sets the threshold when blocked threads get woken up. If it is less than __hwm__ all sleeping producer threads will be woken up if
the amount of pending tasks reaches __lwm__.
[heading Unbounded Queues]
__unbounded_queue__ allows ann unlimited number of tasks to be queued.
The insertion of an __task__ will never block. If the queue becomes empty __worker_threads__ will be set to sleep until new tasks are enqueued.
[heading Task Scheduling]
For scheduling of tasks inside the queue following strategies are available:
* fifo: first enqueued task is dequeued first
* priority: the next item dequeued from the queue depends on its associated priority attribute and sorting criterion applied to the queue (template arguments)
// thread-pool with priority scheduling
// tasks with higher priority are
// scheduled first
boost::task::static_pool< boost::task::unbounded_priority_queue< int > > pool( boost::task::poolsize( 5) );
boost::task::task< void > t1( some_fn);
boost::task::task< void > t2( another_fn);
// move task t1 with priority 5 to thread-pool
boost::task::async(
boost::move( t1),
5,
pool);
// move task t2 with priority 3 to thread-pool
boost::task::async(
boost::move( t2),
3,
pool);
* smart: enqueue- and dequeue-operations are determined by the template arguments und the task-attribute. The library provides an default let only one kind of task stored inside the queue (gets replaced by new one)
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_smart_queue< int > > pool_type;
void main()
{
pool_type pool( boost::task::poolsize( 1) );
...
boost::task::task< long > t1(
boost::bind( fibonacci_fn, 10) );
boost::task::task< long > t2(
boost::bind( fibonacci_fn, 5) );
// replaced by later task with same attribute == 2
// if still pending in pool
boost::task::async(
boost::move( t1),
2,
pool);
// will replace previous pending task with attribute == 2
boost::task::async(
boost::move( t2),
2,
pool);
}
__boost_task__ provides following queues:
* bounded_fifo
* bounded_priority_queue< Attr, Comp = std::less< Attr > >
* bounded_smart_queue< Attr, Comp, Enq = detail::replace_oldest, Deq = detail::take_oldest >
* unbounded_fifo
* unbounded_priority_queue< Attr, Comp = std::less< Attr > >
* unbounded_smart_queue< Attr, Comp, Enq = detail::replace_oldest, Deq = detail::take_oldest >
[endsect]

View File

@@ -1,125 +0,0 @@
[/
Copyright Oliver Kowalke 2009.
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:scheduling Scheduling]
The scheduling policy determines how tasks are scheduled inside the __queue__.
[heading fifo]
First inserted pending __task__ gets taken first.
[heading priority]
Each __task__ is submitted to the pool with a priority attribute. The type and ordering of the priority is user-defined.
``
// thread-pool with priority scheduling
// tasks with higher priority are
// scheduled first
boost::task::static_pool<
boost::task::unbounded_queue<
boost::task::priority< int > >
> pool( boost::task::poolsize( 5) );
boost::task::task< void > t1( some_fn);
boost::task::task< void > t2( another_fn);
// move task t1 with priority 5 to thread-pool
boost::task::async(
boost::move( t1),
5,
pool);
// move task t2 with priority 3 to thread-pool
boost::task::async(
boost::move( t2),
3,
pool);
``
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::greater< Attr >`).
``
// thread-pool with priority scheduling
// tasks with lower priority are
// scheduled first
boost::task::static_pool<
boost::task::unbounded_queue<
boost::task::priority< int, std::less< int > >
>
> pool( boost::task::poolsize( 5) );
``
[heading smart]
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 __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.
``
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_queue<
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) );
...
boost::task::task< long > t1(
boost::bind( fibonacci_fn, 10) );
boost::task::task< long > t2(
boost::bind( fibonacci_fn, 5) );
// replaced by later task with same attribute == 2
// if still pending in pool
boost::task::async(
boost::move( t1),
2,
pool);
// will replace previous pending task with attribute == 2
boost::task::async(
boost::move( t2),
2,
pool);
}
``
[endsect]

View File

@@ -1,106 +0,0 @@
[/
Copyright Oliver Kowalke 2009.
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:pool_shutdown 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.
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.
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_fifo > pool_type;
void main()
{
pool_type pool( boost::task::poolsize( 1) );
...
boost::task::task< long > t1( fibonacci_fn, 10);
boost::task::task< long > t2( fibonacci_fn, 5);
boost::task::handle< long > h1(
boost::task::async(
boost::move( t1),
pool) );
boost::task::handle< long > h2(
boost::task::async(
boost::move( t2),
pool) );
// waits until all pending tasks are finished
pool.shutdown();
std::cout << "fibonacci(10) == " << h1.get() << "\n";
std::cout << "fibonacci(5) == " << h2.get() << std::endl;
}
[note The deconstructor calls __fn_shutdown__ if the pool was not shutdown yet.]
The function __fn_shutdown_now__ closes the pool, interrupts and then joins all __worker_threads__. Pending tasks are unprocessed.
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_fifo > pool_type;
void main()
{
pool_type pool( boost::task::poolsize( 1) );
...
boost::task::task< long > t1( fibonacci_fn, 10);
boost::task::task< long > t2( fibonacci_fn, 5);
boost::task::handle< long > h1(
boost::task::async(
boost::move( t1),
pool) );
boost::task::handle< long > h2(
boost::task::async(
boost::move( t2),
pool) );
// requests task interruption and
// joins all worker-threads
pool.shutdown_now();
// accessing the result may throw task_interrupted
std::cout << "fibonacci(10) == " << h1.get() << "\n";
std::cout << "fibonacci(5) == " << h2.get() << std::endl;
}
[endsect]

View File

@@ -1,47 +0,0 @@
[/
(C) Copyright 2007-8 Anthony Williams.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt).
]
[section:barriers Barriers]
A barrier is a simple concept. Also known as a __rendezvous__, it is a synchronization point between multiple
contexts of execution. The barrier is configured for a particular number of tasks (`n`), and as
tasks reach the barrier they must wait until all `n` tasks have arrived. Once the `n`-th task has reached the
barrier, all the waiting tasks can proceed, and the barrier is reset.
[section:barrier Class `barrier`]
#include <boost/task/spin/barrier.hpp>
class barrier
{
public:
barrier( unsigned int initial);
bool wait();
};
Instances of __spin_barrier__ are not copyable or movable.
[section:constructor `barrier( unsigned int initial)`]
[variablelist
[[Effects:] [Construct a barrier for `initial` tasks.]]
[[Throws:] [__invalid_argument__ if an error occurs.]]
]
[endsect]
[section:wait `bool wait()`]
[variablelist
[[Effects:] [Block until `initial` tasks have called `wait` on `*this`. When the `initial`-th task calls `wait`,
all waiting tasks are unblocked, and the barrier is reset. ]]
[[Returns:] [`true` for exactly one task from each batch of waiting tasks, `false` otherwise.]]
[[Throws:] [__task_error__ if an error occurs.]]
]
[endsect]
[endsect]
[endsect]

View File

@@ -1,199 +0,0 @@
[/
(C) Copyright 2007-8 Anthony Williams.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt).
]
[section:conditions Condition Variables]
[heading Synopsis]
The class `condition` provides a mechanism for one task to wait for notification `condition`. When the task is
woken from the wait, then it checks to see if the appropriate condition is now true, and continues if so. If the
condition is not true, then the task then calls `wait` again to resume waiting. In the simplest case, this
condition is just a boolean variable:
boost::tasks::spin::condition cond;
boost::tasks::spin::mutex mtx;
bool data_ready;
void process_data();
void wait_for_data_to_process()
{
boost::unique_lock< boost::tasks::spin::mutex > lk( mtx);
while ( ! data_ready)
{
cond.wait( lk);
}
process_data();
}
Notice that the `lk` is passed to `wait`: `wait` will atomically add the task to the set of tasks waiting on the
condition variable, and unlock the mutex. When the task is woken, the mutex will be locked again before the call
to `wait` returns. This allows other tasks to acquire the mutex in order to update the shared data, and ensures
that the data associated with the condition is correctly synchronized.
In the mean time, another task sets the condition to `true`, and then calls either `notify_one` or `notify_all` on
the condition variable to wake one waiting task or all the waiting tasks respectively.
void retrieve_data();
void prepare_data();
void prepare_data_for_processing()
{
retrieve_data();
prepare_data();
{
boost::lock_guard< boost::tasks::spin::mutex > lk( mtx);
data_ready = true;
}
cond.notify_one();
}
Note that the same mutex is locked before the shared data is updated, but that the mutex does not have to be locked
across the call to `notify_one`.
[section:condition Class `condition`]
#include <boost/task/spin/condition.hpp>
class condition
{
public:
condition();
~condition();
void notify_one();
void notify_all();
void wait( boost::unique_lock< boost::tasks::spin::mutex > & lk);
template< typename Pred >
void wait( boost::unique_lock< boost::tasks::spin::mutex > & lk, Pred pred);
template< typename LockType >
void wait( LockType & lk);
template< typename LockType, typename Pred >
void wait( LockType & lk, Pred predicate);
void timed_wait( boost::unique_lock< boost::tasks::spin::mutex > & lk, system_time const& abs_time);
template< typename TimeDuration >
void timed_wait( boost::unique_lock< boost::tasks::spin::mutex > & lk, TimeDuration const& rel_time);
template< typename Pred >
void timed_wait( boost::unique_lock< boost::tasks::spin::mutex > & lk, system_time const& abs_time, Pred pred);
template< typename TimeDuration, typename Pred >
void timed_wait( boost::unique_lock< boost::tasks::spin::mutex > & lk, TimeDuration const& rel_time, Pred pred);
template< typename LockType >
void timed_wait( LockType & lk, system_time const& abs_time);
template< typename TimeDuration, typename LockType >
void timed_wait( LockType & lk, TimeDuration const& rel_time);
template< typename LockType, typename Pred >
void timed_wait( LockType & lk, system_time const& abs_time, Pred predicate);
template< typename LockType, typename TimeDuration, typename Pred >
void timed_wait( LockType & lk, TimeDuration const& rel_time, Pred predicate);
};
[section:constructor `condition()`]
[variablelist
[[Effects:] [Constructs an object of class `condition`.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:destructor `~condition()`]
[variablelist
[[Precondition:] [All tasks waiting on `*this` have been notified by a call to `notify_one` or `notify_all`
(though the respective calls to `wait` need not have returned).]]
[[Effects:] [Destroys the object.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:notify_one `void notify_one()`]
[variablelist
[[Effects:] [If any tasks are currently __blocked__ waiting on `*this` in a call to `wait`, unblocks one of
those tasks.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:notify_all `void notify_all()`]
[variablelist
[[Effects:] [If any tasks are currently __blocked__ waiting on `*this` in a call to `wait`, unblocks all of
those tasks.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:wait `void wait( boost::unique_lock< boost::tasks::spin::mutex > & lk)`]
[variablelist
[[Precondition:] [`lk` is locked by the current task, and either no other
task is currently waiting on `*this`, or the execution of the `mutex()` member
function on the `lk` objects supplied in the calls to `wait` in all the tasks
currently waiting on `*this` would return the same value as `lk->mutex()` for
this call to `wait`.]]
[[Effects:] [Atomically call `lk.unlock()` and blocks the current task. The
task will unblock when notified by a call to `this->notify_one()` or
`this->notify_all()`, or spuriously. When the task is unblocked (for whatever
reason), the lock is reacquired by invoking `lk.lock()` before the call to
`wait` returns. The lock is also reacquired by invoking `lk.lock()` if the
function exits with an exception.]]
[[Postcondition:] [`lk` is locked by the current task.]]
[[Throws:] [__task_error__ if an error
occurs. __task_interrupted__ if the wait was interrupted by a call to
__interrupt__ on the __task__ object associated with the current task of execution.]]
]
[endsect]
[section:wait_predicate `template< typename Pred > void wait( boost::unique_lock< boost::tasks::spin::mutex > & lk, Pred pred)`]
[variablelist
[[Effects:] [As-if ``
while ( ! pred())
{
wait( lk);
}
``]]
]
[endsect]
[section:wait_t `template< typename LockType > void wait( LockType & lk)`]
[variablelist
[[Effects:] [Atomically call `lk.unlock()` and blocks the current task. The
task will unblock when notified by a call to `this->notify_one()` or
`this->notify_all()`, or spuriously. When the task is unblocked (for whatever
reason), the lock is reacquired by invoking `lk.lock()` before the call to
`wait` returns. The lock is also reacquired by invoking `lk.lock()` if the
function exits with an exception.]]
[[Postcondition:] [`lk` is locked by the current task.]]
[[Throws:] [__task_error__ if an error
occurs. __task_interrupted__ if the wait was interrupted by a call to
__interrupt__ on the __task__ object associated with the current task of execution.]]
]
[endsect]
[section:wait_predicate_t `template< typename LockType, typename Pred > void wait( LockType & lk, Pred pred)`]
[variablelist
[[Effects:] [As-if ``
while ( ! pred())
{
wait( lock);
}
``]]
]
[endsect]
[endsect]
[endsect]

View File

@@ -1,289 +0,0 @@
[/
(C) Copyright 2009 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:eventvar_ref Event Variables]
[heading Synopsis]
__boost_task__ provides event variables to facilitate coordination between tasks.
A event-variable has two states `set` (`signaled`) or `reset` (`nonsignaled`).
boost::tasks::spin::auto_reset_event ev;
void process_data();
void wait_for_data_to_process()
{
ev.wait();
process_data();
}
`wait` will atomically add the task to the set of tasks waiting on the event
variable. When the task is woken, the event variable will be reset again.
In the mean time, another task signals the event variable by calling
`set` on the event variable to wake one waiting task.
void retrieve_data();
void prepare_data();
void prepare_data_for_processing()
{
retrieve_data();
prepare_data();
ev.set();
}
[section:auto_reset_event Class `auto_reset_event`]
[heading Synopsis]
When the ['auto_reset_event] gets signaled, any one task will see this particular signal. When a task observes
the signal by waiting on the event, it is automatically transitioned back to non-signaled state. Any tasks can
subsequently set the event.
#include <boost/task/spin/auto_reset_event.hpp>
class auto_reset_event : private boost::noncopyable
{
public:
explicit auto_reset_event( bool isset = false);
~auto_reset_event();
void set();
void wait();
bool try_wait();
bool timed_wait( system_time const& abs_time);
templatey typename TimeDuration >
bool timed_wait( TimeDuration const& rel_time);
};
[section:constructor `explicit auto_reset_event( bool isset = false)`]
[variablelist
[[Effects:] [Constructs an object of class `auto_reset_event`. If isset is `true`
the variable is set.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:destructor `~auto_reset_event()`]
[variablelist
[[Precondition:] [All tasks waiting on `*this` have been notified by a call to
`set` (though the respective calls to `wait` need not have returned).]]
[[Effects:] [Destroys the object.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:set `void set()`]
[variablelist
[[Effects:] [If any tasks are currently __blocked__ waiting on `*this` in a call
to `wait`, unblocks one of those tasks.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:wait `void wait()`]
[variablelist
[[Effects:] [Blocks the current task. The task will unblock when notified by a call
to `this->set()`. When the task is unblocked, the variable is reset before `wait`
returns.]]
[[Throws:] [__task_interrupted__ if the wait was interrupted by a call to
__interrupt__ on the __task__ object associated with the current task of execution.]]
]
[endsect]
[section:try_wait `bool try_wait()`]
[variablelist
[[Effects:] [Returns `true` if the event variable is set otherwise `false`.]]
[[Throws:] [Nothing.]]
]
[endsect]
[endsect]
[section:manual_reset_event Class `manual_reset_event`]
[heading Synopsis]
The ['manual_reset_event] remains signaled until it is manually reset. Multiple tasks
wait on the same event and observe the same signal.
#include <boost/task/spin/manual_reset_event.hpp>
class manual_reset_event : private boost::noncopyable
{
public:
explicit manual_reset_event( bool isset = false);
~manual_reset_event();
void set();
void reset();
void wait();
bool try_wait();
bool timed_wait( system_time const& abs_time);
templatey typename TimeDuration >
bool timed_wait( TimeDuration const& rel_time);
};
[section:constructor `explicit manual_reset_event( bool isset = false)`]
[variablelist
[[Effects:] [Constructs an object of class `manual_reset_event`. If isset is `true`
the variable is set.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:destructor `~manual_reset_event()`]
[variablelist
[[Precondition:] [All tasks waiting on `*this` have been notified by a call to
`set` (though the respective calls to `wait` need not have returned).]]
[[Effects:] [Destroys the object.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:set `void set()`]
[variablelist
[[Effects:] [If any tasks are currently __blocked__ waiting on `*this` in a call
to `wait`, unblocks those tasks. The variable remains signaled until `this->reset()`
gets called.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:reset `void reset()`]
[variablelist
[[Effects:] [The event variable gets nonsignaled and tasks calling `this->wait()`
will block.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:wait `void wait()`]
[variablelist
[[Effects:] [Blocks the current task. The task will unblock when notified by a call
to `this->set()`. When the task is unblocked, the variable remains set.]]
[[Throws:] [__task_interrupted__ if the wait was interrupted by a call to
__interrupt__ on the __task__ object associated with the current task of execution.]]
]
[endsect]
[section:trywait `boo try_wait()`]
[variablelist
[[Effects:] [Returns `true` if the event variable is set otherwise `false`.]]
[[Throws:] [Nothing.]]
]
[endsect]
[endsect]
[section:count_down_event Class `count_down_event`]
[heading Synopsis]
The ['count_down_event] decrements an internal counter (set in the constructor) and all
waiting tasks are blocked until the count reaches zero.
#include <boost/task/spin/count_down_event.hpp>
class count_down_event : private boost::noncopyable
{
public:
explicit count_down_event( unsigned int initial);
~count_down_event();
unsigned int initial() const;
unsigned int current() const;
bool is_set() const;
void set();
void wait();
bool timed_wait( system_time const& abs_time);
template< typename TimeDuration >
bool timed_wait( TimeDuration const& rel_time);
};
[section:constructor `explicit count_down_event( unsigned int initial)`]
[variablelist
[[Effects:] [Constructs an object of class `count_down_event` with initial value.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:destructor `~count_down_event()`]
[variablelist
[[Precondition:] [All tasks waiting on `*this` have been notified by a call to
`set` (though the respective calls to `wait` need not have returned).]]
[[Effects:] [Destroys the object.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:initial `unsigned int initial()`]
[variablelist
[[Effects:] [Returns the initial value the event variable was initialized with.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:current `unsigned int current()`]
[variablelist
[[Effects:] [Returns the value the variable currently holds.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:is_set `bool is_set()`]
[variablelist
[[Effects:] [Returns `true` if the varaible has reached zero.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:set `void set()`]
[variablelist
[[Effects:] [Decrements the current count. If the count reaches zero and any tasks are
currently __blocked__ waiting on `*this` in a call to `wait`, unblocks those tasks.
The variable remains signaled.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:wait `void wait()`]
[variablelist
[[Effects:] [Blocks the current task. The task will unblock when notified by a call
to `this->set()` and the count of the event variable reaches zero. When the task is
unblocked, the variable remains set.]]
[[Throws:] [__task_interrupted__ if the wait was interrupted by a call to
__interrupt__ on the __task__ object associated with the current task of execution.]]
]
[endsect]
[endsect]
[endsect]

View File

@@ -1,206 +0,0 @@
[/
Copyright Oliver Kowalke 2009.
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:fifos (Un)Bounded fifos]
__boost_task__ provides a bounded and a unbounded fifo suitable to synchonize tasks via message passing.
typedef boost::tasks::spin::unbounded_channel< int > fifo_t;
void send( fifo_t fifo)
{
for ( int i = 0; i < 5; ++i)
fifo.put( i);
fifo.deactivate();
}
void recv( fifo_t fifo)
{
boost::optional< int > value;
while ( fifo.take( value) )
{ std::cout << "received " << * value << std::endl; }
}
boost::tasks::scheduler<> sched;
fifo_t fifo;
sched.make_task( send, fifo);
sched.make_task( recv, fifo);
for (;;)
{
while ( sched.run() );
if ( sched.empty() ) break;
}
[section:unbounded_channel Class template `unbounded_channel`]
#include <boost/task/spin/unbounded_channel.hpp>
template< typename T >
class unbounded_channel : private noncopyable
{
public:
unbounded_channel();
void deactivate();
bool empty();
void put( T const& t);
bool take( boost::optional< T > & va);
bool take( boost::optional< T > & va, system_time const& abs_time);
template< typename TimeDuration >
bool take( boost::optional< T > & va, TimeDuration const& rel_time);
bool try_take( boost::optional< T > & va);
};
[section:constructor `unbounded_channel()`]
[variablelist
[[Effects:] [Constructs an object of class `unbounded_channel`.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:deactivate `void deactivate()`]
[variablelist
[[Effects:] [Deactivates the fifo. No values can be put after calling `this->deactivate`. tasks blocked in
`this->take()` will be return.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:empty `bool empty()`]
[variablelist
[[Effects:] [Returns `true` if the fifo currently contains no data.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:put `void put( T const& t)`]
[variablelist
[[Effects:] [Enqueues the value in the fifo and wakes up a task waiting for new data available from the
fifo.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:take `bool take( boost::optional< T > & va)`]
[variablelist
[[Effects:] [Dequeues a value from the fifo. If no data is available from the fifo the task gets suspended until
new data are enqueued (return value `true` and va contains dequeued value) or the fifo gets deactiveted and
the function returns `false`.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:try_take `bool try_take( boost::optional< T > & va)`]
[variablelist
[[Effects:] [Dequeues a value from the fifo. If no data is available from the fifo the function returns `false`.
Otherwise it returns `true` and `va` contains the dequed value.]]
[[Throws:] [Nothing.]]
]
[endsect]
[endsect]
[section:bounded_channel Class template `bounded_channel`]
#include <boost/task/spin/bounded_channel.hpp>
template< typename T >
class bounded_channel : private noncopyable
{
public:
bounded_channel( std::size_t wm);
bounded_channel( std::size_t hwm, std::size_t lwm);
void deactivate();
bool empty();
void put( T const& t);
void put( T const& t, system_time const& abs_time);
template< typename TimeDuration >
void put( T const& t, TimeDuration const& rel_time);
bool take( boost::optional< T > & va);
bool take( boost::optional< T > & va, system_time const& abs_time);
template< typename TimeDuration >
bool take( boost::optional< T > & va, TimeDuration const& rel_time);
bool try_take( boost::optional< T > & va);
};
[section:constructor `bounded_channel( std::size_t wm)`]
[variablelist
[[Effects:] [Constructs an object of class `bounded_channel` which will contain a maximum of `wm` items.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:constructor2 `bounded_channel( std::size_t hwm, std::size_t lwm)`]
[variablelist
[[Effects:] [Constructs an object of class `bounded_channel` which will contain a maximum of `hwm` items.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:deactivate `void deactivate()`]
[variablelist
[[Effects:] [Deactivates the fifo. No values can be put after calling `this->deactivate`. tasks blocked in
`this->take()` will be return.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:empty `bool empty()`]
[variablelist
[[Effects:] [Returns `true` if the fifo currently contains no data.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:put `void put( T const& t)`]
[variablelist
[[Effects:] [Enqueues the value in the fifo and wakes up a task waiting for new data available from the
fifo. If the watermark has reached the task putting the value will be supended until at least one item
was dequeued.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:take `bool take( boost::optional< T > & va)`]
[variablelist
[[Effects:] [Dequeues a value from the fifo. If no data is available from the fifo the task gets suspended until
new data are enqueued (return value `true` and va contains dequeued value) or the fifo gets deactiveted and
the function returns `false`.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:try_take `bool try_take( boost::optional< T > & va)`]
[variablelist
[[Effects:] [Dequeues a value from the fifo. If no data is available from the fifo the function returns `false`.
Otherwise it returns `true` and `va` contains the dequed value.]]
[[Throws:] [Nothing.]]
]
[endsect]
[endsect]
[endsect]

View File

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

View File

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

View File

@@ -1,43 +0,0 @@
[/
(C) Copyright 2007-8 Anthony Williams.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt).
]
[section:mutex_types Mutex Types]
[section:mutex Class `mutex`]
#include <boost/tasks/spin/mutex.hpp>
class mutex : private boost::noncopyable
{
public:
mutex();
~mutex();
void lock();
bool timed_lock( system_time const& abs_time);
template< typename TimeDuration >
bool timed_lock( TimeDuration const& rel_time);
bool try_lock();
void unlock();
typedef unique_lock< mutex > scoped_lock;
};
__spin_mutex__ implements the __lockable_concept__ to provide an exclusive-ownership mutex. At most one task can own the
lock on a given instance of __spin_mutex__ at any time. Multiple concurrent calls to __lock__, __try_lock__ and
__unlock__ shall be permitted.
[note __spin_mutex__ is ['not] bound to a __scheduler__ and can only be used by tasks
managed by different schedulers or code not running in a task.]
[endsect]
[endsect]

View File

@@ -1,18 +0,0 @@
[/
Copyright Oliver Kowalke 2009.
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:spin_synchronization Synchronization]
Synch. objects using spin-wait ops. reside in namespace `boost::tasks::spin`.
[include spin_mutexes.qbk]
[include spin_condition_variables.qbk]
[include spin_barrier.qbk]
[include spin_event_variables.qbk]
[include spin_fifos.qbk]
[include spin_futures.qbk]
[endsect]

View File

@@ -1,301 +0,0 @@
[/
Copyright Oliver Kowalke 2009.
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:static_pool Thread-Pool with fixed ]
__boost_task__ provides __static_pool__ - which contains an fixed set of pre-forked __worker_threads__ (the size of the pool doesn't change during its lifetime).
__static_pool__ supports move semantics.
boost::task::_static_pool< // pool type
boost::task::unbounded_fifo // queue where application threads enqueue tasks
> pool(
boost::task::poolsize( 6), // pool with 6 pre-forked worker-threads
boost::posix_time::posix_time::milliseconds( 50), // time to sleep if no work-item available
boost::task::scanns( 10) ); // iterations over local-queues before sleep
The first argument of the constructor specifies how many __worker_threads__ the pool will contain. The second
and third argument are used by the [link_work_stealing __work_stealing__] algorithm.
[note If __bounded_queue__ is used as queuing policy the constructor has two additional arguments . ]
__static_pool__ provides functionality to check the status of the pool - __fn_closed__ returns true when the pool was
shutdown and __fn_size__returns the number of __worker_threads__.
[section:static_pool Class template `static_pool`]
#include <boost/task/static_pool.hpp>
template< typename Channel >
class static_pool : private noncopyable
{
public:
static_pool();
explicit static_pool(
poolsize const& psize,
posix_time::time_duration const& asleep = posix_time::microseconds( 10),
scanns const& scns = scanns( 20) );
explicit static_pool(
poolsize const& psize,
high_watermark const& hwm,
low_watermark const& lwm,
posix_time::time_duration const& asleep = posix_time::milliseconds( 100),
scanns const& scns = scanns( 20) );
static_pool( static_pool &&);
static_pool & operator=( static_pool &&);
# if defined(BOOST_HAS_PROCESSOR_BINDINGS)
explicit static_pool(
<<unspec-type>>,
posix_time::time_duration const& asleep = posix_time::microseconds( 10),
scanns const& scns = scanns( 20) );
explicit static_pool(
<<unspec-type>>,
high_watermark const& hwm,
low_watermark const& lwm,
posix_time::time_duration const& asleep = posix_time::milliseconds( 100),
scanns const& scns = scanns( 20) );
static <<unspec-type>> bind_to_processors();
# endif
~static_pool();
std::size_t size();
void shutdown();
void shutdown_now();
bool closed();
void interrupt_all_worker();
const std::size_t upper_bound();
void upper_bound( high_watermark const& hwm);
const std::size_t lower_bound();
void lower_bound( low_watermark const& lwm);
template< typename R >
handle< R > submit( task< R > && t);
template< typename R, typename Attr >
handle< R > submit( task< R > && t, Attr const& attr);
void swap( static_pool & other);
operator unspecified_bool_type() const;
bool operator!() const;
};
[section `static_pool()`]
[variablelist
[[Effects:] [constructs an unitialized pool]]
[[Throws:] [nothing]]
]
[endsect]
[section `explicit static_pool(
<<unspec-type>>,
posix_time::time_duration const& asleep = posix_time::microseconds( 10),
scanns const& scns = scanns( 20) )`]
[variablelist
[[Preconditions:] [operating system provides functionality for processor binding]]
[[Effects:] [constructs a pool - for each processor a worker-thread is created and bound to one processor - global-queue can queue an unlimited number of tasks]]
[[Throws:] [`boost::thread_resource_error`, `boost::task::invalid_scanns`, `boost::task::invalid_timeduration`]]
[[Notes:] [constructor has to be called if a unbounded-queue is used and `bind_to_processors()` must be set as first argument]]
]
[endsect]
[section `explicit static_pool(
poolsize const& psize,
posix_time::time_duration const& asleep = posix_time::microseconds( 10),
scanns const& scns = scanns( 20) )`]
[variablelist
[[Effects:] [constructs a pool containing psize worker-threads - global-queue can queue an unlimited number of tasks]]
[[Throws:] [`boost::thread_resource_error`, `boost::task::invalid_scanns`, `boost::task::invalid_timeduration`]]
[[Notes:] [constructor has to be called if a unbounded-queue is used]]
]
[endsect]
[section `explicit static_pool(
<<unspec-type>>,
high_watermark const& hwm,
low_watermark const& lwm,
posix_time::time_duration const& asleep = posix_time::milliseconds( 100),
scanns const& scns = scanns( 20) )`]
[variablelist
[[Preconditions:] [operating system provides functionality for processor binding]]
[[Effects:] [constructs a pool - for each processor a worker-thread is created and bound to one processor - global-queue can only queue a limited number of tasks]]
[[Throws:] [`boost::thread_resource_error`, `boost::task::invalid_scanns`, `boost::task::invalid_timeduration`, `boost::task::invalid_watermark`]]
[[Notes:] [constructor has to be called if a bounded-queue is used and `bind_to_processors()` must be set as first argument]]
]
[endsect]
[section `explicit static_pool(
poolsize const& psize,
high_watermark const& hwm,
low_watermark const& lwm,
posix_time::time_duration const& asleep = posix_time::milliseconds( 100),
scanns const& scns = scanns( 20) )`]
[variablelist
[[Effects:] [constructs a pool containing psize worker-threads - global-queue can only queue a limited number of tasks]]
[[Throws:] [`boost::thread_resource_error`, `boost::task::invalid_scanns`, `boost::task::invalid_timeduration`, `boost::task::invalid_watermark`]]
[[Notes:] [constructor has to be called if a bounded-queue is used]]
]
[endsect]
[section `static_pool( static_pool &&)`]
[variablelist
[[Effects:] [creates an pool out of another one which gets zeroed out]]
[[Throws:] [nothing]]
]
[endsect]
[section `static_pool & operator=( static_pool &&)`]
[variablelist
[[Effects:] [creates an pool out of another one which gets zeroed out]]
[[Throws:] [nothing]]
]
[endsect]
[section `~static_pool()`]
[variablelist
[[Effects:] [calls `shutdown()` if not already called]]
[[Throws:] [nothing]]
]
[endsect]
[section `<<unspec-type>> bind_to_processors()`]
[variablelist
[[Effects:] [used in order to let the pool create worker-threads as cores are available and bound the threads to the cores]]
[[Throws:] [nothing]]
]
[endsect]
[section `std::size_t size()`]
[variablelist
[[Effects:] [returns how many worker-threads are running in the pool]]
[[Throws:] [`boost::task::pool_moved`]]
]
[endsect]
[section `void shutdown()`]
[variablelist
[[Effects:] [deactivates the queue and joins all worker-threads - the pool is closed]]
[[Throws:] [`boost::thread_interrupted`, `boost::system::system_error`, `boost::task::pool_moved`]]
[[Notes:] [all pending tasks are processed]]
]
[endsect]
[section `void shutdown_now()`]
[variablelist
[[Effects:] [deactivates the queue, send interruption request to all worker-threads and joins them - the pool is closed]]
[[Throws:] [`boost::thread_interrupted`, `boost::system::system_error`, `boost::task::pool_moved`]]
[[Notes:] [pending tasks are not processed but returned]]
]
[endsect]
[section `void interrupt_all_worker()`]
[variablelist
[[Effects:] [interrupts all worker-threads without invalidating the pool]]
[[Throws:] [nothing]]
]
[endsect]
[section `bool closed()`]
[variablelist
[[Effects:] [queries if the pool is closed (pool is shutdown)]]
[[Throws:] [`boost::task::pool_moved`]]
]
[endsect]
[section `std::size_t upper_bound()`]
[variablelist
[[Preconditions:] [queue is of type bounded-queue]]
[[Effects:] [returns the upper bound of the bounded-queue]]
[[Throws:] [`boost::task::pool_moved`]]
[[Notes:] [can only be used if a bounded-queue is used]]
]
[endsect]
[section `void upper_bound( high_watermark const& hwm)`]
[variablelist
[[Preconditions:] [queue is of type bounded-queue]]
[[Effects:] [sets the upper bound of the bounded-queue]]
[[Postconditions:] [`this->upper_bound() == hwm`]]
[[Throws:] [`boost::task::invalid_watermark`, `boost::task::pool_moved`]]
[[Notes:] [can only be used if a bounded-queue is used]]
]
[endsect]
[section `std::size_t lower_bound()`]
[variablelist
[[Preconditions:] [queue is of type bounded-queue]]
[[Effects:] [returns the lower bound of the bounded-queue]]
[[Throws:] [`boost::task::pool_moved`]]
[[Notes:] [can only be used if a bounded-queue is used]]
]
[endsect]
[section `void lower_bound( low_watermark const& lwm)`]
[variablelist
[[Preconditions:] [queue is of type bounded-queue]]
[[Effects:] [sets the lower bound of the bounded-queue]]
[[Postconditions:] [`this->lower_bound() == lwm`]]
[[Throws:] [`boost::task::invalid_watermark`, `boost::task::pool_moved`]]
[[Notes:] [can only be used if a bounded-queue is used]]
]
[endsect]
[section `template< typename R > handle< R > submit( task< R > t)`]
[variablelist
[[Preconditions:] [has_attribute< pool >::value == false && ! closed()]]
[[Effects:] [moves an task to the pool and returns an associated handle]]
[[Throws:] [`boost::task::task_rejected`, `boost::task::pool_moved`]]
]
[endsect]
[section `template< typename R, typename Attr > handle< R > submit( task< R > t, Attr const& attr)`]
[variablelist
[[Preconditions:] [has_attribute< pool >::value == true && ! closed()]]
[[Effects:] [moves an task to the pool and returns an associated handle - task is scheduled by the attribute]]
[[Throws:] [`boost::task::task_rejected`, `boost::task::pool_moved`]]
]
[endsect]
[section `void swap( static_pool & other)`]
[variablelist
[[Effects:] [swaps pool]]
[[Throws:] [nothing]]
]
[endsect]
[section `operator unspecified_bool_type() const`]
[variablelist
[[Effects:] [is static_pool valid == does static_pool own ownership]]
[[Throws:] [Nothing]]
]
[endsect]
[section `bool operator!() const`]
[variablelist
[[Effects:] [is static_pool invalid == static_pool does not have ownership]]
[[Throws:] [Nothing]]
]
[endsect]
[endsect]
[endsect]

Some files were not shown because too many files have changed in this diff Show More