re-use context

This commit is contained in:
Oliver Kowalke
2017-03-28 19:47:25 +02:00
parent e1ab9d051a
commit 58fadf45d4
5 changed files with 56 additions and 58 deletions
+8 -28
View File
@@ -10,41 +10,21 @@
#include <boost/fiber/all.hpp>
inline
void fn( std::string const& str, int n)
{
for ( int i = 0; i < n; ++i)
{
std::cout << i << ": " << str << std::endl;
boost::this_fiber::yield();
}
void fn( std::string const& str, int n) {
std::cout << n << ": " << str << std::endl;
}
void foo() {
try
{
int main() {
try {
boost::fibers::fiber f1( fn, "abc", 5);
std::cerr << "f1 : " << f1.get_id() << std::endl;
f1.join();
}
catch ( std::exception const& e)
{ std::cerr << "exception: " << e.what() << std::endl; }
catch (...)
{ std::cerr << "unhandled exception" << std::endl; }
}
int main()
{
try
{
foo();
std::cout << "done." << std::endl;
return EXIT_SUCCESS;
} catch ( std::exception const& e) {
std::cerr << "exception: " << e.what() << std::endl;
} catch (...) {
std::cerr << "unhandled exception" << std::endl;
}
catch ( std::exception const& e)
{ std::cerr << "exception: " << e.what() << std::endl; }
catch (...)
{ std::cerr << "unhandled exception" << std::endl; }
return EXIT_FAILURE;
}
+12 -26
View File
@@ -161,6 +161,12 @@ public:
private:
friend class scheduler;
enum flag_t {
context_initial = 1 << 0,
context_finish = 1 << 1,
context_terminated = 1 << 2
};
struct fss_data {
void * vp{ nullptr };
detail::fss_cleanup_function::ptr_t cleanup_function{};
@@ -192,7 +198,7 @@ private:
std::atomic< context * > remote_nxt_{ nullptr };
#endif
alignas(cache_alignment) detail::spinlock splk_{};
bool terminated_{ false };
unsigned int flags_{ context_initial };
wait_queue_t wait_queue_{};
public:
detail::wait_hook wait_hook_{};
@@ -312,7 +318,7 @@ public:
std::allocator_arg, palloc, salloc,
[this](boost::context::continuation && c_){
boost::context::continuation c = c_.resume();
for (;;) { // TODO: termination condition?
while ( 0 == ( flags_ & context_finish) ) {
suspend();
}
// terminate context
@@ -344,6 +350,10 @@ public:
else return false;
}
void finish() noexcept {
flags_ |= context_finish;
}
void release() noexcept;
#if (BOOST_EXECUTION_CONTEXT==1)
@@ -366,29 +376,6 @@ public:
template< typename Fn, typename Tpl >
void inject( Fn && fn, Tpl && tpl) noexcept {
c_ = c_.resume_with(
# if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
detail::wrap(
[this]( typename std::decay< Fn >::type & fn, typename std::decay< Tpl >::type & tpl,
boost::context::continuation && c_) mutable noexcept {
boost::context::continuation c = c_.resume();
detail::data_t * dp = c.get_data< detail::data_t * >();
// update continuation of calling fiber
dp->from->c_ = std::move( c);
if ( nullptr != dp->lk) {
dp->lk->unlock();
} else if ( nullptr != dp->ctx) {
context::active()->schedule_( dp->ctx);
}
# if defined(BOOST_NO_CXX17_STD_APPLY)
boost::context::detail::apply( std::move( fn), std::move( tpl) );
# else
std::apply( std::move( fn), std::move( tpl) );
# endif
release();
},
std::forward< Fn >( fn),
std::forward< Tpl >( tpl) )
# else
[this,fn=detail::decay_copy( std::forward< Fn >( fn) ),tpl=std::forward< Tpl >( tpl)]
(boost::context::continuation && c_) mutable noexcept {
boost::context::continuation c = c_.resume();
@@ -407,7 +394,6 @@ public:
# endif
release();
}
# endif
);
}
#endif
+2
View File
@@ -112,6 +112,8 @@ private:
context * main_ctx_{ nullptr };
bool shutdown_{ false };
void release_free_() noexcept;
void release_terminated_() noexcept;
#if ! defined(BOOST_FIBERS_NO_ATOMICS)
+5 -3
View File
@@ -325,7 +325,7 @@ context::join() {
// protect for concurrent access
std::unique_lock< detail::spinlock > lk{ splk_ };
// wait for context which is not terminated
if ( ! terminated_) {
if ( 0 == (flags_ & context_terminated) ) {
// push active context to wait-queue, member
// of the context which has to be joined by
// the active context
@@ -348,8 +348,9 @@ void
context::terminate() noexcept {
// protect for concurrent access
std::unique_lock< detail::spinlock > lk{ splk_ };
BOOST_ASSERT( 0 == ( flags_ & context_finish) );
// mark as terminated
terminated_ = true;
flags_ |= context_terminated;
// notify all waiting fibers
while ( ! wait_queue_.empty() ) {
context * ctx = & wait_queue_.front();
@@ -383,8 +384,9 @@ boost::context::continuation
context::terminate() noexcept {
// protect for concurrent access
std::unique_lock< detail::spinlock > lk{ splk_ };
BOOST_ASSERT( 0 == ( flags_ & context_finish) );
// mark as terminated
terminated_ = true;
flags_ |= context_terminated;
// notify all waiting fibers
while ( ! wait_queue_.empty() ) {
context * ctx = & wait_queue_.front();
+29 -1
View File
@@ -22,6 +22,30 @@
namespace boost {
namespace fibers {
void
scheduler::release_free_() noexcept {
while ( ! free_queue_.empty() ) {
context * ctx = & free_queue_.front();
free_queue_.pop_front();
BOOST_ASSERT( ctx->is_context( type::worker_context) );
BOOST_ASSERT( ! ctx->is_context( type::pinned_context) );
BOOST_ASSERT( this == ctx->get_scheduler() );
BOOST_ASSERT( ctx->is_resumable() );
BOOST_ASSERT( ctx->worker_is_linked() );
BOOST_ASSERT( ! ctx->ready_is_linked() );
#if ! defined(BOOST_FIBERS_NO_ATOMICS)
BOOST_ASSERT( ! ctx->remote_ready_is_linked() );
#endif
BOOST_ASSERT( ! ctx->sleep_is_linked() );
BOOST_ASSERT( ! ctx->free_is_linked() );
BOOST_ASSERT( ! ctx->wait_is_linked() );
BOOST_ASSERT( ctx->wait_queue_.empty() );
BOOST_ASSERT( 0 == ( ctx->flags_ & context::context_finish) );
BOOST_ASSERT( 0 == ( ctx->flags_ & context::context_terminated) );
ctx->finish();
}
}
void
scheduler::release_terminated_() noexcept {
while ( ! terminated_queue_.empty() ) {
@@ -37,9 +61,11 @@ scheduler::release_terminated_() noexcept {
BOOST_ASSERT( ! ctx->remote_ready_is_linked() );
#endif
BOOST_ASSERT( ! ctx->sleep_is_linked() );
BOOST_ASSERT( ! ctx->free_is_linked() );
BOOST_ASSERT( ! ctx->wait_is_linked() );
BOOST_ASSERT( ctx->wait_queue_.empty() );
BOOST_ASSERT( ctx->terminated_);
BOOST_ASSERT( 0 != ( ctx->flags_ & context::context_finish) );
BOOST_ASSERT( 0 != ( ctx->flags_ & context::context_terminated) );
// if last reference, e.g. fiber::join() or fiber::detach()
// have been already called, this will call ~context(),
// the context is automatically removeid from worker-queue
@@ -114,6 +140,8 @@ scheduler::~scheduler() {
#endif
// signal dispatcher-context termination
shutdown_ = true;
// release context from free-queue
release_free_();
// resume pending fibers
// by joining dispatcher-context
dispatcher_ctx_->join();