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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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 ;
|
||||
@@ -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
|
||||
;
|
||||
@@ -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]
|
||||
@@ -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]
|
||||
@@ -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]
|
||||
@@ -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]
|
||||
@@ -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]
|
||||
@@ -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]
|
||||
@@ -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]
|
||||
@@ -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]
|
||||
@@ -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]
|
||||
|
||||
|
||||
@@ -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 'Sutter’s 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]
|
||||
@@ -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]
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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]
|
||||
@@ -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]
|
||||
@@ -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]
|
||||
@@ -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]
|
||||
@@ -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]
|
||||
@@ -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]
|
||||
@@ -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]
|
||||
@@ -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]
|
||||
@@ -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]
|
||||
@@ -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]
|
||||
@@ -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]
|
||||
@@ -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
Reference in New Issue
Block a user