mirror of
https://github.com/boostorg/fiber.git
synced 2026-07-21 13:13:32 +00:00
re-use context
This commit is contained in:
+8
-28
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user