Giter Site home page Giter Site logo

fiber's Introduction

Boost.fiber

Boost.fiber provides a framework for micro-/userland-threads (fibers) scheduled cooperatively. The API contains classes and functions to manage and synchronize fibers similar to boost.thread.

A fiber is able to store the current execution state, including all registers and CPU flags, the instruction pointer, and the stack pointer and later restore this state. The idea is to have multiple execution paths running on a single thread using a sort of cooperative scheduling (threads are preemptively scheduled) - the running fiber decides explicitly when it yields to allow another fiber to run (context switching).

A context switch between threads costs usually thousands of CPU cycles on x86 compared to a fiber switch with less than 100 cycles. A fiber can only run on a single thread at any point in time.

Boost.fiber requires C++11!

fiber's People

Contributors

absolute8511 avatar benjaminw3 avatar brad0 avatar brandon-kohn avatar ctrysbita avatar danielae avatar davidoc26 avatar dixlorenz avatar djarek avatar ecatmur avatar eguesnet avatar eldiener avatar gjasny avatar glenfe avatar grafikrobot avatar hailios avatar ingomueller-net avatar jbeich avatar kivadiu avatar kraj avatar kumar-shivam-ranjan avatar martinitus avatar mlang avatar nat-goodspeed avatar neheb avatar olk avatar pdimov avatar romain-geissler-1a avatar tex avatar xaqq avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fiber's Issues

ASIO: unbuffered_channel / scheduler notify issue

Hello,

I've spent more time trying to use both asio and fiber together. I am now aware that proper integration is still pending support in asio.

However, I've faced a few issues that made the combined use of asio and fiber not usable (for my use case).


Consider the following test program:

std::shared_ptr<boost::fibers::unbuffered_channel<int>> c;

void run_t1()
{
    auto io_ptr = std::make_shared<boost::asio::io_service>();
    boost::fibers::use_scheduling_algorithm<boost::fibers::asio::round_robin>(io_ptr);

    boost::fibers::fiber f([](){
        for (int i = 0; i < 10; ++i) {
            std::cout << "Will push " << i << std::endl;
            c->push(i);
        }
    });

    f.detach();
    io_ptr->run();
}

void run_t2()
{
    auto io_ptr = std::make_shared<boost::asio::io_service>();
    boost::fibers::use_scheduling_algorithm<boost::fibers::asio::round_robin>(io_ptr);

    boost::fibers::fiber f([](){
        try {
            for (;;) {
                int i = c->value_pop();
                std::cout << "Read " << i << " from channel." << std::endl;
            }
        }
        catch (const std::exception &e)
        {
            std::cout << "Caught: " << e.what() << std::endl;
        }
    });

    f.detach();
    io_ptr->run();
}

int main() {
    c = std::make_shared<boost::fibers::unbuffered_channel<int>>();

    std::thread t1(run_t1);
    std::thread t2(run_t2);

    t2.join();
    t1.join();
    return 0;
}

The expected output would be for the fiber in run_t2 to display number ranging from 0 to 9. However, in my test, the output was either:

  • No number (value_pop() never returned, not even once).
  • Read number 0 and/or 1.

It never managed to read the 10 numbers from the channel. I again tried to dive into the library,
trying to understand what was happening.
I believe I've found the cause and have a fix, but I still struggle to reason about what's happening under the hood so I might be wrong.

I believe the issue lies in boost::fibers::asio::round_robin's notify() method. The method simply
make the timer expires now(). In the past I guess this was okay, but since commit de58b07 the lambda posted in the round_robin::service's contructor does not yield() anymore. This means that when that lambda is awakened due to the timer expiring, it doesn't give a chance to other fiber to run.

The fix consist of adding an async_wait() that would run yield().
I'll submit a PR with the fix shortly. Note that some of the comment are probably outdated, but I'm not
comfortable enough to update them.

Please let me know if my understanding of the issue is wrong.

has_ready_fibers() always returns true

Hello,

I've been playing with boost::fibers and I've found something strange that might be a bug. It might also be me misusing / misunderstand how things work.
Initially, my goal was to integrate asio and fibers, so I've ready the tutorial and used the fibers::asio::round_robin algorithm.

Consider the following simple program.

int main()
{
   // assert(!boost::fibers::has_ready_fibers()); Assertion would fail. Weird?
    boost::asio::io_service io_service_;
    boost::fibers::use_scheduling_algorithm<boost::fibers::asio::round_robin>(io_service_);
    io_service_.run();
    return 0;
}

This causes the program to run at 100% cpu usage. I've tried to debug a bit, but without much success. It seems that has_ready_fibers() always returns true, causing the CPU to spin.
As you can see, even without setting any scheduling algorithm, has_ready_fibers() returns true when there should be no such ready fibers.


I've tried to show the issue with an even simpler program. So I've added debug print in the library and recompiled.

This is the modified has_ready_fibers() for boost::fibers::algo::round_robin (the default algorithm)

// The modified has_ready_fibers() for debug output
bool
round_robin::has_ready_fibers() const noexcept {
	std::cout << "In has_ready_fibers(), will list ready fibers. Current fiber id: "
            << context::active()->get_id() << std::endl;
  for (const auto &f : rqueue_)
    {
      std::cout << "\tFiber: " << f.get_id() << std::endl;
    }
  return ! rqueue_.empty();
}

And this is the corresponding program that shows the issue.

#include <iostream>
#include <boost/asio.hpp>
#include <boost/fiber/all.hpp>

int main()
{
  std::cout << "My fiber id: " << boost::this_fiber::get_id() << std::endl;
  boost::fibers::has_ready_fibers();
}

/*
 The follwing is outputed by the program.
My fiber id: 0x1d5f270
In has_ready_fibers(), will list ready fibers. Current fiber id: 0x1d5f270
        Fiber: 0x1d6f3a8
*/

It seems there is a fiber that comes from I don't know where, and seems to cause some
issue.

Now it's quite possible that I'm missing something, so please let me know if that's the case.
Thanks,

Question regarding yield

Hi there, Sorry for the noob question. From my understanding calling yield from within a fiber will cause the fiber scheduler to give cycles to another fiber. Now suppose I have a IO call that would block and during the block I would like to give other fibers the cycles. Consider this:

...
do_nb_stuff(); // do non blocking stuff
yield(); // <------if I put yield here won't it context switch before the do_b_stuff?
do_b_stuff(); // do blocking work
yield(); // <------if I put yield here won't it context switch after the do_b_stuff?

What I want is to yield during do_b_stuff if that makes sense.

Thanks and sorry for my stupidity or lack of understanding in advance.

protected class members for shared_work scheduler

Hi,

First of all, thanks for the great contributions of fibers to the boost libraries!

I used fibers to build a runtime system for a distributed database system and had the need to create a custom scheduler. The scheduler that I needed was pretty similar to your provided shared_work scheduler with the caveat that the "system" or dispatcher fibers must be scheduled with some frequency to garbage-collect terminated tasks. I proceeded to derive my scheduler from your shared_work but unfortunately needed to change your code to declare the members of the shared_work class to be protected instead of private.

Would it be possible to change these class members to be protected so that they can be accessed by derived classes?

Thanks,

Daniel Chavarria
Trovares Inc.

Cannot create a fiber with the tip of Boost.Context on g++ 5.2.1

When trying to use Boost.Fiber with the tip of Boost.Context, I get a horrendous compilation error with basic use -- attached.

// Event the simplest case does not work:
boost::fibers::fiber f([] () {});

It looks like this broke with this change in Boost.Context: 43d89cb6396706871ce9378c8e3b2c63e93ffe0e - support passing argument between execution_context.

The preceding commit works perfectly fine for me: 01660915c1330a186ed0548b436065a9fc8ec96c

My compiler is g++ 5.2.1.

Initialization order fiasco

Hello!

It looks like thread local context::active_ depends on another thread local - activation_record::current_rec.

image

Then it crashes

image

incorrect std::memory_order value in compare_exchange_strong?

detail/spinlock_ttas_adaptive_futex.hpp#L69
detail/spinlock_ttas_futex.hpp#L65
unbuffered_channel.hpp#L242
unbuffered_channel.hpp#L292
unbuffered_channel.hpp#L74
unbuffered_channel.hpp#L89

http://en.cppreference.com/w/cpp/atomic/atomic/compare_exchange

failure - the memory synchronization ordering for the load operation if the comparison fails. Cannot be std::memory_order_release or std::memory_order_acq_rel [and cannot specify stronger ordering than success (until C++17)]

ASIO timer example

Hi. Thanks for this library! What is the best practice for using timer callbacks (asio + fibers)? I can see simple tcp example (echo), and the code is clear. But it would be great if example with asio timers would appear (or piece of code).
Thanks in advance!

example yield.hpp possibly destroys locked mutex

I posted this on the boost bugtracker however it wasnt noticed by anyone, so ill post it here.

In the examples/asio/detail/yield.hpp file, the sleeping fiber owns the mutex(for when async_result::get returns, the asio call returns and the yield_completion is destroyed).
Consider Fiber A, the callee of the async operation, and Fiber B, the fiber that calls async_handler.
Fiber B possibly runs in another thread.

Fiber B locks the mutex, sets fiber A as ready and goes to sleep without releasing the lock. Fiber A goes through the return process and destroys the mutex.

The solution is very simple. Simply reaquire the lock after the suspend call returns.

Assertion failure in schedule_from_remote

Under Boost 1.64 and 1.63 using this boiled down example on Windows
(VS2015) when the condition is signaled, inside
scheduler::schedule_from_remote(ctx), the assertion
!ctx->sleep_is_linked() fails. I do not believe this is occuring
under Linux.

While testing, I tried using condition wait without the timeout, and
it behaves fine. Looking closer, it appears that
scheduler::schedule(ctx) actually checks sleep_is_linked() and
unlinks when true.

Am I using conditions incorrectly, or is
scheduler::schedule_from_remote doing the wrong thing? Maybe it
should be checking sleep_is_linked, and unlinking also, being careful
to protect against multithreaded access?

#include <boost/fiber/condition_variable.hpp>
#include <boost/fiber/fiber.hpp>
#include <boost/fiber/mutex.hpp>
#include <boost/thread.hpp>

boost::fibers::mutex g_mutex;
boost::fibers::condition_variable g_condition;

void thread1()
{
  Sleep(1000); // Wait for the other thread to get going.
  printf("about to signal\n");
  g_condition.notify_one();
}

int main()
{
  boost::thread t(thread1);

  std::unique_lock<boost::fibers::mutex> lk(g_mutex);
  printf("about to wait\n");
  g_condition.wait_for(lk, std::chrono::seconds(5));
  printf("done\n");

  return 0;
}

Passing a fixed_stack allocator to async/packaged_task doesn't compile on gcc 5.4

I'm trying to rewrite the skynet test using async to compare with HPX's implementation. When I tried the following cases it fails to compile as it expects the stack allocator to conform to alloc_traits.h (i.e. define value_type etc.)

    for (std::uint64_t i = 0; i != div; ++i)
    {
        std::uint64_t sub_num = num + i * size;
        boost::fibers::packaged_task<std::uint64_t(allocator_type&, std::uint64_t, std::uint64_t, std::uint64_t)> pt{std::allocator_arg, salloc, skynet };
        boost::fibers::future<std::uint64_t> f{ pt.get_future() };
        boost::fibers::fiber{ boost::fibers::launch::dispatch, std::allocator_arg, salloc,
            std::move(pt), std::ref(salloc), sub_num, size, div }.detach();
        results.push_back(f);
        //results.push_back(boost::fibers::async(
        //      boost::fibers::launch::dispatch
        //    , std::allocator_arg, salloc
        //    , skynet
        //    , std::ref(salloc), sub_num, size, div));
    }

Here's the error message:

/usr/include/c++/5/bits/alloc_traits.h:88:43: error: no type named ‘value_type’ in ‘class boost::context::basic_fixedsize_stackboost::context::stack_traits’
typedef typename _Alloc::value_type value_type;

Apologies if it's something silly I've missed.

context::suspend() is inherently racy

The purpose of the context::suspend() function is to enable low-overhead integration of other frameworks and boost::fiber. Using it however is almost impossible without introducing races. Assume that we want to integrate existing code that performs some asynchronous action. We want it to suspend the current fiber and resume it on completion. This results in the following code:

// Queue of all blocked fibers.
boost::intrusive::list<boost::fibers::context> queue;

// In a multithreaded environment we must protect the queue.
std::mutex mutex;

std::unique_lock<std::mutex> lock{mutex};
// Initiate the asynchronous action.
boost::fibers::active().wait_link(queue);
lock.unlock();
// RACE: Another thread can take the mutex, invoke set_ready() and yield() to the fiber
// here even though it is not suspended yet!
boost::fibers::context::suspend();

I do not see how this race can be avoided with the current design of suspend(). Internally the race is avoided by using the suspend(detail::spin_lock &) overload. That interface however is not documented and inflexible.

I propose that suspend() should be replaced either by

// Futex-style: Suspend the fiber. Then evaluate the predicate and immediately
// set_ready() the fiber if it evaluates to true.
template<typename P> // Must be a bool() function object.
void suspend_if(P predicate);

or by

// Suspend the fiber and evaluate the cleanup function in the scheduler's context.
template<typename F>
void suspend(F cleanup);

These functions would be more flexible than suspend(detail::spin_lock &): For example they allow synchronization via std::atomic instead of spinlocks. Another option would be implementing the proposed std::synchronic class for fibers.

`buffered_channel::try_push` does not wake fibers in `pop`

Against boost 1.63 on amd64 linux

Calls to try_push never cause any fibers already waiting on the channel to wake up.

#include <cassert>
#include <boost/fiber/all.hpp>

int main() {
    boost::fibers::buffered_channel<int> channel(16);

    auto f = boost::fibers::async([&]{
        channel.value_pop();
    });

    boost::this_fiber::sleep_for(std::chrono::seconds(1));

    // Hangs in `f.get()`
    auto push_result = channel.try_push(0);
    
    // Completes
    // auto push_result = channel.push(0);
    
    // Completes with out waiting
    // auto push_result = channel.push_wait_for(0, std::chrono::minutes(1));

    assert(push_result == boost::fibers::channel_op_status::success);

    f.get();
}

I've noticed that try_push is in the class synopsis, but not explicitly documented as it was on the deprecated channel types. Is it supposed to have identical behaviour to bounded_channel?

ASIO's still spinning

Hello @olk

In #101 I mentioned noticing some weird behavior under Valgrind.
It turns out that the issue is not Valgrind related, and after much trouble, I managed to
reproduce it in a simple example. Very similar to the one in #100.

Consider the following program:

std::shared_ptr<boost::fibers::unbuffered_channel<int>> c;
std::shared_ptr<boost::fibers::unbuffered_channel<int>> c2;

void run_t1()
{
    std::atomic_thread_fence(std::memory_order_acquire);
    auto io_ptr = std::make_shared<boost::asio::io_service>();
    boost::fibers::use_scheduling_algorithm<boost::fibers::asio::round_robin>(io_ptr);

    io_ptr->post([&](){
        for (int i = 0 ; i < 50 ; ++i)
        {
            std::stringstream ss;
            ss << "Will push " << i << std::endl;
            std::cout << ss.str();

            c->push(i);
            c2->value_pop(); //spin at this point, until t2 has pushed something.
        }
    });
    io_ptr->run();
}

void run_t2()
{
    std::atomic_thread_fence(std::memory_order_acquire);
    auto io_ptr = std::make_shared<boost::asio::io_service>();
    boost::fibers::use_scheduling_algorithm<boost::fibers::asio::round_robin>(io_ptr);

    boost::fibers::fiber f([io_ptr](){
        try {
            for (;;) {
                int i = c->value_pop();
                std::cout << "Read " << i << " from channel." << std::endl;
                std::this_thread::sleep_for(std::chrono::milliseconds(1000));
                c2->push(i);
            }
        }
        catch (const std::exception &e)
        {
            std::cout << "Caught: " << e.what() << std::endl;
        }
        io_ptr->post([io_ptr](){
            io_ptr->stop();
        });
    });

    io_ptr->run();
}

int main() {
    c = std::make_shared<boost::fibers::unbuffered_channel<int>>();
    c2 = std::make_shared<boost::fibers::unbuffered_channel<int>>();

    std::atomic_thread_fence(std::memory_order_release);
    std::thread t2(run_t2);

    std::this_thread::sleep_for(std::chrono::milliseconds(2000));
    std::thread t1(run_t1);

    t2.join();
    t1.join();
    return 0;
}

The program will spin at 100% cpu.
I'm not sure we are supposed to initiate fiber-related operations (channel's push() / pop()) from a manually post()ed handler (as done in run_t1()), but I would expect we should be able to.

I've tried to fix it in the fibers::asio::round_robin() algorithm, but I didn't managed to.
What I've observed that may help fixing the issue:

  • It seems t1 thread is spinning when it calls value_pop(). It will spin untill the this_thread::sleep() call in t2() returns and a value is pushed (therefore value_pop() is able to complete).
  • The spin in value_pop() seem to come from the infinite loop in the scheduler::dispatch(). asio::round_robin::suspend_until() is called, but return immediately, therefore spinning. It returns immediately because when doing cdn_.notify_one(), no one is actually waiting on cnd_, so the fiber context doesn't change, and suspend_until() is called in a loop.

skynet variants crash on windows

I'm trying to run the skynet benchmarks on windows, and find that they all crash. I build with visual studio 2015 and tag boost-1.63.0.

The crash is an access violation down in context:

skynet.exe!boost::intrusive::list_node_traits<void * __ptr64>::set_next(boost::intrusive::list_node<void *> * const & n, boost::intrusive::list_node<void *> * const & next) Line 66 C++
skynet.exe!boost::intrusive::circular_list_algorithms<boost::intrusive::list_node_traits<void * __ptr64> >::unlink(boost::intrusive::list_node<void *> * const & this_node) Line 146 C++
skynet.exe!boost::intrusive::list_impl<boost::intrusive::mhtraits<boost::fibers::context,boost::intrusive::list_member_hook<boost::intrusive::tagboost::fibers::detail::ready_tag,boost::intrusive::link_mode<2>,void>,104>,unsigned __int64,0,void>::pop_front_and_disposeboost::intrusive::detail::null_disposer(boost::intrusive::detail::null_disposer disposer) Line 349 C++
skynet.exe!boost::fibers::algo::round_robin::pick_next() Line 36 C++
skynet.exe!boost::fibers::scheduler::dispatch() Line 153 C++
skynet.exe!boost::fibers::context::(boost::context::execution_context<boost::fibers::detail::data_t *> ctx, boost::fibers::detail::data_t * dp) Line 225 C++
[External Code]
skynet.exe!make_fcontext() Line 158 Unknown

Some Questions.(and About Using fiber.join)

I use this boost-fiber in my game engine, and get these questions:

  1. Is it highly real-time?
  2. A problem... I uses fiber.join() as fiber.resume in ruby(enter the fiber and continue), uses boost::this_fiber::yield() as Fiber.yield in ruby(return to father fiber), and get wrong result, then I write a piece of code:
int main(){
    boost::fibers::fiber f([&] {
        while (true) {
            puts("ppp");
            boost::this_fiber::yield();
        }
    });
    while (true) {
        f.join()
        puts("qqq");
    }
    return 0;
}

As what I thinked, it should print as:

ppp
qqq
ppp
qqq
.......

But in fact it print:

ppp
ppp
ppp
ppp
....

It seems like boost::this_fiber::yield() does not return where the fiber was called.
What should I do? Thanks a lot, I am tired of 6 hours working on config boost and using fibers..

buffered_channel failed to compile with g++ 4.8 on Ubuntu

I am trying to compile the code example with g++4.8 on Ubuntu 14.04 in the tutorial from boost website
http://www.boost.org/doc/libs/1_63_0/libs/fiber/doc/html/fiber/synchronization/channels/buffered_channel.html

And it failed with the following error:

opt/third_party/include/boost/fiber/buffered_channel.hpp: In instantiation of ‘boost::fibers::buffered_channel::buffered_channel(std::size_t) [with T = HAUD::SS7Wrapper*; std::size_t = long unsigned int]’:
/home/ak70/HaudDevelopment/HaudCore/HaudCore/Services/HaudSMSService/HaudEndpointWorker.cpp:23:25: required from here
/opt/third_party/include/boost/fiber/buffered_channel.hpp:49:9: error: use of deleted function ‘std::atomic::atomic(const std::atomic&)’
slot() = default;
^
In file included from /home/ak70/HaudDevelopment/HaudCore/HaudCore/Services/HaudSMSService/HaudWorkerJob.h:11:0,
from /home/ak70/HaudDevelopment/HaudCore/HaudCore/Services/HaudSMSService/HaudEndpointWorker.h:16,
from /home/ak70/HaudDevelopment/HaudCore/HaudCore/Services/HaudSMSService/HaudEndpointWorker.cpp:7:
/usr/include/c++/4.8/atomic:658:7: error: declared here
atomic(const atomic&) = delete;
^
In file included from /opt/third_party/include/boost/fiber/all.hpp:15:0,
from /home/ak70/HaudDevelopment/HaudCore/HaudCore/Services/HaudSMSService/HaudWorkerJob.h:19,
from /home/ak70/HaudDevelopment/HaudCore/HaudCore/Services/HaudSMSService/HaudEndpointWorker.h:16,
from /home/ak70/HaudDevelopment/HaudCore/HaudCore/Services/HaudSMSService/HaudEndpointWorker.cpp:7:
/opt/third_party/include/boost/fiber/buffered_channel.hpp:138:16: note: synthesized method ‘boost::fibers::buffered_channel::slot::slot() [with T = HAUD::SS7Wrapper*]’ first required here
slots_ = new slotcapacity_;
^
Any ideas?

cannot compile on master

hello.
i cannot compile this code on the master branche, only on the develop branche (it was so for a few month). now on the develop branche it compiles but crashes (terminated by signal SIGSEGV (Address boundary error)). i am on db88147

#include <iostream>
#include <boost/fiber/all.hpp>

int main(int argc, char** argv) {
        boost::fibers::fiber([](){std::cout << "hello from fiber" << std::endl;}).detach();
        boost::this_fiber::yield();

        return 0;
}

Build problem

Hi,

I have built and installed boost 1.62 and I'm trying to build a simple fiber program using the following command:

clang++ fiber.cpp -std=c++14 -I /usr/local/include/boost/ -l boost_context -l boost_system -l boost_thread -l pthread

But I'm getting undefined references to:

  • boost::fibers::fiber::start_()
  • boost::fibers::context::active()
  • boost::fibers::context::set_ready_(boost::fibers::context*)
  • boost::fibers::context::set_terminated()

The program:

#include <iostream>
#include <boost/fiber/all.hpp>

int main(int argc, char const *argv[]) {
  auto fiber = boost::fibers::fiber([] () {
    std::cout << "Hello World" << std::endl;
  });
  return 0;
}

boost::fiber 1.64.0 fails to compile with Visual Studio v140_xp toolchain

I'm trying to compile boost::fiber with Visual Studio 2017 and it's v140_xp toolchain (that is the Visual Studio 2015 toolchain for Windows XP support - don't ask ...) targeting Windows XP 32bit.

As it is not directly possible with b2 to define the toolchain name for VS, one needs to set it via environment variables as described in this MS official blog post ("Targeting from the Command Line").

With the following batch file (to be run from within the Developer Command Prompt for VS 2017):

:: Setting additional parameters for XP toolchain
set INCLUDE=%ProgramFiles(x86)%\Microsoft SDKs\Windows\7.1A\Include;%INCLUDE%
set PATH=%ProgramFiles(x86)%\Microsoft SDKs\Windows\7.1A\Bin;%PATH%
set LIB=%ProgramFiles(x86)%\Microsoft SDKs\Windows\7.1A\Lib;%LIB%
set CL=/D_USING_V140_SDK71_;%CL%

call b2.exe --layout=versioned -q variant=debug,release link=static runtime-link=shared threading=multi cxxflags=/vmg linkflags=/SUBSYSTEM:CONSOLE,5.01 toolset=msvc-14.0 stage

boost::fiber fails to compile with the following error:

compile-c-c++ ..\all_build_fiber\boost\bin.v2\libs\fiber\build\msvc-14.0\debug\link-static\threading-multi\algo\algorithm.obj
algorithm.cpp
D:\3rdparty\boost\1.64.0\src\boost/intrusive/detail/parent_from_member.hpp(52): error C2338: sizeof(caster) == sizeof(int)
D:\3rdparty\boost\1.64.0\src\boost/intrusive/detail/parent_from_member.hpp(110): note: see reference to function template instantiation 'ptrdiff_t boost::intrusive::detail::offset_from_pointer_to_member<boost::fibers::context,Member>(const Member boost::fibers::context::* )' being compiled
        with
        [
            Member=boost::fibers::detail::wait_functor::hook_type
        ]
D:\3rdparty\boost\1.64.0\src\boost/intrusive/parent_from_member.hpp(42): note: see reference to function template instantiation 'const Parent *boost::intrusive::detail::parent_from_member<boost::fibers::context,Member>(const Member *,const Member boost::fibers::context::* )' being compiled
        with
        [
            Parent=boost::fibers::context,
            Member=boost::fibers::detail::wait_functor::hook_type
        ]
D:\3rdparty\boost\1.64.0\src\boost/fiber/context.hpp(598): note: see reference to function template instantiation 'const Parent *boost::intrusive::get_parent_from_member<boost::fibers::context,boost::fibers::detail::wait_functor::hook_type>(const Member *,const Member boost::fibers::context::* )' being compiled
        with
        [
            Parent=boost::fibers::context,
            Member=boost::fibers::detail::wait_functor::hook_type
        ]

    call "C:\Users\TORBJO~1\AppData\Local\Temp\b2_msvc_14.0_vcvarsall_x86.cmd" >nul
cl /Zm800 -nologo @"..\all_build_fiber\boost\bin.v2\libs\fiber\build\msvc-14.0\debug\link-static\threading-multi\algo\algorithm.obj.rsp" 

...failed compile-c-c++ ..\all_build_fiber\boost\bin.v2\libs\fiber\build\msvc-14.0\debug\link-static\threading-multi\algo\algorithm.obj...

Wake up the sleeped fiber as soon as possible

in
void
fiber_manager::run()
{
....
{
// no fibers ready to run; the thread should sleep
// until earliest fiber is scheduled to run
clock_type::time_point wakeup( next_wakeup() );
this_thread::sleep_until( wakeup);
}
return;
}
while there is no fibers ready, the thread got sleep at least next_wakeup() time. I think there can be a better way to wait on some fd so that another thread can wake it up immediatly by write data to the fd.

Compile errors with recent boost

There are multiple compile errors with boost 1.57 (beta1) and clang 3.6 in c++11 mode:

clang++11 -I ../include -o simple simple.cpp

In file included from simple.cpp:8:
In file included from ../include/boost/fiber/all.hpp:11:
In file included from ../include/boost/fiber/barrier.hpp:16:
In file included from ../include/boost/fiber/condition.hpp:24:
../include/boost/fiber/detail/scheduler.hpp:59:14: error: no viable conversion
from 'detail::thread_local_ptr<fiber_manager>' to
'boost::fibers::fiber_manager '
{ return t
; }
^~
../include/boost/fiber/detail/scheduler.hpp:86:26: note: in instantiation of
member function
'boost::fibers::detail::thread_local_ptrboost::fibers::fiber_manager::get'
requested here
if ( ! instance_.get() )
^
../include/boost/fiber/detail/scheduler.hpp:71:10: error: no viable overloaded
'='
{ t_ = t; }
~~ ^ ~
../include/boost/fiber/detail/scheduler.hpp:87:23: note: in instantiation of
member function
'boost::fibers::detail::thread_local_ptrboost::fibers::fiber_manager::reset'
requested here
instance_.reset( new fiber_manager() );
^
../include/boost/fiber/detail/scheduler.hpp:36:7: note: candidate function (the
implicit copy assignment operator) not viable: no known conversion from
'boost::fibers::fiber_manager *' to 'const
boost::fibers::detail::thread_local_ptrboost::fibers::fiber_manager' for
1st argument
class thread_local_ptr : private noncopyable
^
In file included from simple.cpp:8:
In file included from ../include/boost/fiber/all.hpp:11:
In file included from ../include/boost/fiber/barrier.hpp:16:
In file included from ../include/boost/fiber/condition.hpp:24:
In file included from ../include/boost/fiber/detail/scheduler.hpp:20:
In file included from ../include/boost/fiber/fiber_manager.hpp:20:
../include/boost/fiber/fiber.hpp:109:32: error: call to 'forward' is ambiguous
detail::setup< Fn > s( forward< Fn >( fn), & coro);
^~~~~~~~~~~~~
simple.cpp:24:30: note: in instantiation of function template specialization
'boost::fibers::fiber::fiber<boost::bi::bind_t<void, void ()(const
std::__1::basic_string &, int),
boost::_bi::list2<boost::_bi::value<const char >, boost::_bi::value
> > >' requested here
boost::fibers::fiber f1( boost::bind( fn, "abc", 5) );
^
/opt/local/libexec/llvm-3.6/bin/../include/c++/v1/type_traits:1612:1: note:
candidate function [with _Tp = boost::_bi::bind_t<void, void (
)(const
std::__1::basic_string &, int),
boost::_bi::list2<boost::_bi::value<const char >, boost::_bi::value
> >]
forward(typename std::remove_reference<_Tp>::type& __t) _NOEXCEPT
^
/opt/local/include/boost/move/utility_core.hpp:219:21: note: candidate function
[with T = boost::_bi::bind_t<void, void (
)(const
std::__1::basic_string &, int),
boost::_bi::list2<boost::_bi::value<const char >, boost::bi::value
> >]
inline T&& forward(typename ::boost::move_detail::remove_refere...
^
In file included from simple.cpp:8:
In file included from ../include/boost/fiber/all.hpp:11:
In file included from ../include/boost/fiber/barrier.hpp:16:
In file included from ../include/boost/fiber/condition.hpp:24:
In file included from ../include/boost/fiber/detail/scheduler.hpp:20:
In file included from ../include/boost/fiber/fiber_manager.hpp:20:
In file included from ../include/boost/fiber/fiber.hpp:25:
../include/boost/fiber/detail/trampoline.hpp:46:13: error: call to 'forward' is
ambiguous
Fn fn
( forward< Fn >( from->fn) );
^~~~~~~~~~~~~
../include/boost/fiber/fiber.hpp:108:50: note: in instantiation of function
template specialization
'boost::fibers::detail::trampoline<boost::_bi::bind_t<void, void (
)(const
std::__1::basic_string &, int),
boost::_bi::list2<boost::_bi::value<const char >, boost::_bi::value
> > >' requested here
typename coro_t::call_type coro( detail::trampoline< Fn >, attrs...
^
simple.cpp:24:30: note: in instantiation of function template specialization
'boost::fibers::fiber::fiber<boost::_bi::bind_t<void, void (
)(const
std::__1::basic_string &, int),
boost::_bi::list2<boost::_bi::value<const char >, boost::_bi::value
> > >' requested here
boost::fibers::fiber f1( boost::bind( fn, "abc", 5) );
^
/opt/local/libexec/llvm-3.6/bin/../include/c++/v1/type_traits:1612:1: note:
candidate function [with _Tp = boost::_bi::bind_t<void, void (
)(const
std::__1::basic_string &, int),
boost::_bi::list2<boost::_bi::value<const char >, boost::_bi::value
> >]
forward(typename std::remove_reference<_Tp>::type& __t) _NOEXCEPT
^
/opt/local/include/boost/move/utility_core.hpp:219:21: note: candidate function
[with T = boost::_bi::bind_t<void, void (
)(const
std::__1::basic_string &, int),
boost::_bi::list2<boost::_bi::value<const char *>, boost::bi::value
> >]
inline T&& forward(typename ::boost::move_detail::remove_refere...
^
In file included from simple.cpp:8:
In file included from ../include/boost/fiber/all.hpp:11:
In file included from ../include/boost/fiber/barrier.hpp:16:
In file included from ../include/boost/fiber/condition.hpp:24:
In file included from ../include/boost/fiber/detail/scheduler.hpp:20:
In file included from ../include/boost/fiber/fiber_manager.hpp:18:
In file included from ../include/boost/fiber/detail/waiting_queue.hpp:19:
In file included from ../include/boost/fiber/detail/worker_fiber.hpp:18:
In file included from /opt/local/include/boost/coroutine/symmetric_coroutine.hpp:12:
In file included from /opt/local/include/boost/coroutine/detail/symmetric_coroutine_call.hpp:18:
/opt/local/include/boost/coroutine/detail/symmetric_coroutine_object.hpp:39:25: error:
data member instantiated with function type 'void
(boost::coroutines::detail::symmetric_coroutine_yield<void *> &)'
Fn fn
;
^
/opt/local/include/boost/coroutine/detail/symmetric_coroutine_call.hpp:122:72: note:
in instantiation of template class
'boost::coroutines::detail::symmetric_coroutine_object<void *, void
(boost::coroutines::detail::symmetric_coroutine_yield<void *> &),
boost::coroutines::basic_standard_stack_allocatorboost::coroutines::stack_traits
>' requested here
internal_stack_ctx.sp = static_cast< char * >( stack_ctx.sp) - sizeof( o...
^
../include/boost/fiber/fiber.hpp:108:36: note: in instantiation of function
template specialization
'boost::coroutines::detail::symmetric_coroutine_call<void
*>::symmetric_coroutine_call<void
(boost::coroutines::detail::symmetric_coroutine_yield<void > &)>'
requested here
typename coro_t::call_type coro( detail::trampoline< Fn >, attrs...
^
simple.cpp:24:30: note: in instantiation of function template specialization
'boost::fibers::fiber::fiber<boost::_bi::bind_t<void, void (
)(const
std::__1::basic_string &, int),
boost::_bi::list2<boost::_bi::value<const char *>, boost::bi::value
> > >' requested here
boost::fibers::fiber f1( boost::bind( fn, "abc", 5) );
^
In file included from simple.cpp:8:
In file included from ../include/boost/fiber/all.hpp:11:
In file included from ../include/boost/fiber/barrier.hpp:16:
In file included from ../include/boost/fiber/condition.hpp:24:
In file included from ../include/boost/fiber/detail/scheduler.hpp:20:
In file included from ../include/boost/fiber/fiber_manager.hpp:18:
In file included from ../include/boost/fiber/detail/waiting_queue.hpp:19:
In file included from ../include/boost/fiber/detail/worker_fiber.hpp:18:
In file included from /opt/local/include/boost/coroutine/symmetric_coroutine.hpp:12:
/opt/local/include/boost/coroutine/detail/symmetric_coroutine_call.hpp:127:15: error:
assigning to 'impl_type *' (aka 'symmetric_coroutine_impl<void *> *') from
incompatible type 'object_t *' (aka 'symmetric_coroutine_object<void *,
void (boost::coroutines::detail::symmetric_coroutine_yield<void *> &),
stack_allocator> *')
impl
= new ( internal_stack_ctx.sp) object_t(
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../include/boost/fiber/fiber.hpp:108:36: note: in instantiation of function
template specialization
'boost::coroutines::detail::symmetric_coroutine_call<void
*>::symmetric_coroutine_call<void
(boost::coroutines::detail::symmetric_coroutine_yield<void > &)>'
requested here
typename coro_t::call_type coro( detail::trampoline< Fn >, attrs...
^
simple.cpp:24:30: note: in instantiation of function template specialization
'boost::fibers::fiber::fiber<boost::_bi::bind_t<void, void (
)(const
std::__1::basic_string &, int),
boost::_bi::list2<boost::_bi::value<const char *>, boost::_bi::value
> > >' requested here
boost::fibers::fiber f1( boost::bind( fn, "abc", 5) );
^
6 errors generated.

future::wait_for() will error if timeout occurred before set_value

compiler: vc2017 WIN32
boost: 1.64 --with-context --with-fiber asmflags=/safeseh
code:

    boost::fibers::promise<void> p; // 1
    
    boost::fibers::fiber f(boost::fibers::launch::dispatch, [&p]() mutable {
        auto f = p.get_future(); // 2
        auto r = f.wait_for(std::chrono::seconds{0}); // 3
    });
    p.set_value(); //4 crash!
    boost::this_fiber::yield(); //5

    f.join();

error message:

Assertion failed: ! ctx->ready_is_linked(), file libs\fiber\src\scheduler.cpp, line 223

Release version of shared library broken (at least for Asio code)

Hi Oliver,

This is the issue that was traced down in #29. I encountered it today again with another application. Because #29 was originally not about this problem, and you closed it meanwhile anyway, I'm opening a new one.

Problem: When dynamically linking against the RELEASE version of the Boost Fiber shared library, compilation and linking are successful, but when the binary is run, it fails.
The problem occurs with the "official" Boost Fiber Asio examples, and also with two different applications of mine.

When dynamically linking against the debug shared library, or statically linking against either the debug or release static library, everything works.

Note: I have tested this only with code using Asio. I don't know if the issue affects non-Asio Fibers code.

Environment: Ubuntu 14.04 64-bit, GCC 4.9.2, latest Modular Boost, latest Boost Fiber (develop) branch

To reproduce it with the official examples:

  1. cd /modboost-folder/libs/fiber/examples
  2. Change Jamfile.v2:
    -      <link>static
    +      <link>shared
    +      <linkflags>-lboost_context
    +      <linkflags>-lboost_thread
    
  3. debug build:
    • b2 toolset=gcc cxxflags="-std=c++14" address-model=64 architecture=x86 debug
      cd /modboost-folder/bin.v2/libs/fiber/examples/gcc-4.9.2/debug/address-model-64/architecture-x86/threading-multi/asio
    • In one terminal ./echo_server 1234, in another ./echo_client 127.0.0.1 1234
    • Works
  4. release build
    • b2 toolset=gcc cxxflags="-std=c++14" address-model=64 architecture=x86 release
      cd /modboost-folder/bin.v2/libs/fiber/examples/gcc-4.9.2/release/address-model-64/architecture-x86/threading-multi/asio
    • In one terminal ./echo_server 1234, in another ./echo_client 127.0.0.1 1234
    • Doesn't work

Erratic crashes in testsuite

When running fiber's testsuite, I experience erratic crashes in these test cases:

  • test_future_dispatch
  • test_future_post
  • test_shared_future_dispatch
  • test_shared_future_post

For example, my latest run (branch develop) crashed in three cases:

testing.capture-output Z:\boost\bin.v2\libs\fiber\test\test_future_post.test\msvc-14.1\rls\adrs-mdl-64\lnk-sttc\thrd-mlt\test_future_post.run
====== BEGIN OUTPUT ======
Running 24 test cases...
unknown location(0): fatal error: in "Boost.Fiber: future test suite/test_future_wait_until_void": memory access violation
test_future_post.cpp(516): last checkpoint

*** 1 failure is detected in the test module "Master Test Suite"
 
EXIT STATUS: -1073741819 
====== END OUTPUT ======

testing.capture-output Z:\boost\bin.v2\libs\fiber\test\test_shared_future_post.test\msvc-14.1\rls\adrs-mdl-64\lnk-sttc\thrd-mlt\test_shared_future_post.run
====== BEGIN OUTPUT ======
Running 22 test cases...
unknown location(0): fatal error: in "Boost.Fiber: shared_future test suite/test_shared_future_wait_until": memory access violation
test_shared_future_post.cpp(449): last checkpoint

*** 1 failure is detected in the test module "Master Test Suite"
 
EXIT STATUS: -1073741819 
====== END OUTPUT ======

testing.capture-output Z:\boost\bin.v2\libs\fiber\test\test_shared_future_dispatch.test\msvc-14.1\rls\adrs-mdl-64\lnk-sttc\thrd-mlt\test_shared_future_dispatch.run
====== BEGIN OUTPUT ======
Running 22 test cases...
unknown location(0): fatal error: in "Boost.Fiber: shared_future test suite/test_shared_future_wait_with_fiber_1": memory access violation
test_shared_future_dispatch.cpp(508): last checkpoint

*** 1 failure is detected in the test module "Master Test Suite"
 
EXIT STATUS: -1073741819 
====== END OUTPUT ======

From another run earlier at the same day:

testing.capture-output Z:\boost\bin.v2\libs\fiber\test\test_shared_future_post.test\msvc-14.1\rls\adrs-mdl-64\lnk-sttc\thrd-mlt\test_shared_future_post.run
====== BEGIN OUTPUT ======
Running 22 test cases...
unknown location(0): fatal error: in "Boost.Fiber: shared_future test suite/test_shared_future_wait_until_ref": memory access violation
test_shared_future_post.cpp(469): last checkpoint

*** 1 failure is detected in the test module "Master Test Suite"
 
EXIT STATUS: -1073741819 
====== END OUTPUT ======

testing.capture-output Z:\boost\bin.v2\libs\fiber\test\test_future_dispatch.test\msvc-14.1\rls\adrs-mdl-64\lnk-sttc\thrd-mlt\test_future_dispatch.run
====== BEGIN OUTPUT ======
Running 24 test cases...
unknown location(0): fatal error: in "Boost.Fiber: future test suite/test_future_wait_with_fiber_1": memory access violation
test_future_dispatch.cpp(535): last checkpoint

*** 1 failure is detected in the test module "Master Test Suite"
 
EXIT STATUS: -1073741819 
====== END OUTPUT ======

The test runs are conducted on Windows 10 1703, Intel Core i7-6700K (4+4 Cores at 4 GHz), MSVC 14.1 (same with 14.0), 64 Bit, up to 6 parallel Jam tasks, parallel build, both debug and release mode. I've instrumented Boost.Test such that these errors are captured in the test log.

ASIO yield completion

I believe I may have found a race condition pertaining to the ASIO completion handler.

In the current implementation, a fiber may be scheduled when it was never suspended.

the check: if ( fibers::context::active() != ctx_) {
in yield_handler_base::operator() is in no way a guarantee that a fiber needs to be rescheduled.

I have solved this issue in my local implementation by implementing the following:

                 struct yield_completion {

			typedef fibers::detail::spinlock                    mutex_t;
			typedef std::unique_lock< mutex_t >                 lock_t;
			typedef boost::intrusive_ptr< yield_completion >    ptr_t;

			std::atomic< std::size_t >		use_count_{ 0 };
			mutex_t							mtx_{};
			enum complete_state {init, waiting, complete};
			complete_state								completed_{ init };

			void wait() {
				// yield_handler_base::operator()() will set completed_ true and
				// attempt to wake a suspended fiber. It would be Bad if that call
				// happened between our detecting (! completed_) and suspending.
				// If completed_ is already set, we're done here: don't suspend.

				lock_t lk{ mtx_ };

				if (!(completed_ == complete)) {
					// suspend(unique_lock<spinlock>) unlocks the lock in the act of
					// resuming another fiber

					completed_ = waiting;

					fibers::context::active()->suspend(lk);
				}
			}
`

`
                        // completion callback passing only (error_code)
			void operator()(boost::system::error_code const& ec) {
				BOOST_ASSERT_MSG(ycomp_,
					"Must inject yield_completion* "
					"before calling yield_handler_base::operator()()");
				BOOST_ASSERT_MSG(yt_.ec_,
					"Must inject boost::system::error_code* "
					"before calling yield_handler_base::operator()()");
				// If originating fiber is busy testing completed_ flag, wait until it
				// has observed (! completed_).

				yield_completion::lock_t lk{ ycomp_->mtx_ };

				auto status = ycomp_->completed_;

				// Notify a subsequent yield_completion::wait() call that it need not
				// suspend.
				ycomp_->completed_ = yield_completion::complete;
				// set the error_code bound by yield_t
				*yt_.ec_ = ec;

				// unlock the lock that protects completed_
				lk.unlock();

				// If ctx_ is still active, e.g. because the async operation
				// immediately called its callback (this method!) before the asio
				// async function called async_result_base::get(), we must not 
				// schedule it, because it was suspended.
				if (status == yield_completion::waiting) {
					// wake the calling fiber
					ctx_->get_scheduler()->schedule_from_remote(ctx_);
//					fibers::context::active()->schedule(ctx_);
				}
			}

Also, see the last line of code above? I changed it from:

				fibers::context::active()->schedule(ctx_);

to:

					ctx_->get_scheduler()->schedule_from_remote(ctx_);

This change means that nothing fiber/scheduler wise is created in an thread running io_service::run();

I believe I found where this same change can be implemented to condition_variable and the result would be to notify a condition from a non-fiber thread with little performance penalty.

I know this is a simple description. I can attempt to explain more if necessary. But, right now my head hurts so bad right now from figuring this out!!!

Thoughts?

Custom fiber properties and scheduling

Hi Oliver,

I have different types of fibers, and I'd need a scheduler that makes scheduling decisions based on the fiber type (or any custom property of the fiber). I could approximate what I want with fiber priorities, which used to exist in the master branch.

Is there any good way to do this in the develop branch? I haven't found one.

A derived class of fiber doesn't help, because the scheduler works with fiber_context.
Creating derived classes of both fiber and fiber_context could work, but currently it doesn't, due to two issues: in fiber, the wrapped fiber_context is hidden as a private member, and fiber is not polymorphic, its methods aren't virtual. So even if I would reimplement all methods of fiber in my derived fiber class in order to use my derived fiber_context, it would not work.

Having a way to do this type of customization would be very useful, probably for many people.
The easiest solution would be to change the the private section of fiber to protected. However, Asio spawn() would have to be modified to support the custom fiber types, too.

Thanks!

Scheduler redesign proposal

The scheduler currently has the following issues for my design:

  • Algorithm is called even after main fiber is destructed, making it impossible to depend on stack-based data
  • No way to do a collaborative scheduler, since fibers are locked too much on one thread (scheduler)

The fix proposal is:

  • Making the fibers more like std::thread, which defines a crash if any thread remains after main() exit. In that case, we don't need to do any call to scheduler when destructing.
  • Move timers, remote ready functionality to algorithm, possibly with a pre-implemented virtual function

Which branch to use currently?

Hello Oliver,

A project I'm working on will rely on Boost Fiber and I have to start using the library in the next few days.
Which branch is the one you recommend to use currently? The master is very old, so I was looking at develop, but there are some newer ones, too.

Thank you for the great libraries!

Garbage collection of completed tasks

Hi,

Another general issue that appeared in my experience with fiber is that completed tasks do not release their memory until the dispatcher/system fiber runs.

The dispatcher fiber is not scheduled in all (?) / most(?) schedulers unless there are no application fibers pending. It would be great to provide another mechanism to garbage collect completed tasks, either by the user calling a function or by having the dispatcher fiber scheduled with some other priority.

Thanks,

Daniel Chavarria
Trovares Inc.

movable channels?

Both bound and unbound channels are not copyable nor movable, and thus it cannot be used with std container.

It's possible to make a channel movable or I have to resort to a vector of [shared|unique] pointers?

Develop branch and Asio?

Hello Oliver,

I contacted you a week ago to ask which development branch to use. I saw that in the meantime develop became the one.

I just got around to starting to work with Boost Fiber. I built it with modular Boost (which btw. wasn't trivial) and wanted to re-read the Asio examples and start coding. I have to use Fibers together with Asio. Unfortunately, I saw that yesterday you have first modified and then deleted the Asio-related examples. Doesn't the integration with Asio work anymore? If so, then what do you recommend? Can the Asio-related problems be fixed easily? Or should I use an older commit or the old master branch?

Thank you very much!

Best regards,
Emil

PS: my use of Fibers would be simple: One main fiber that creates other fibers for doing some work. This work includes asynchronous I/O through Asio, for which the fiber should yield. I'd also like to have a simple scheduler. All fibers would run on the same thread.

Fiber requirements fail when cross-compiling

If I try to cross-compile Boost.Fiber for the armv6 architecture, the cxx11_* requirements in the Jamfile.v2 will fail, because the building system will try to execute the binaries on the host.

This should not happen.
The fact that the binaries are compiled is enough to guarantee the cxx11_* support by the compiler.

Assertion "! ctx->ready_is_linked()" when using condition_variable::wait_for

When i use condition_variable::wait_for in multipliy fibers program crashes with assertion:
"Assertion failed: ! ctx->ready_is_linked(), file libs\fiber\src\scheduler.cpp, line 192".

Minimal sample:

#include <boost/fiber/all.hpp>
#include <mutex>
#include <thread>
#include <chrono>

int main()
{
    boost::fibers::condition_variable condvar;
    boost::fibers::mutex mutex;

    auto do_work = [&]()
    {
        while (true)
        {
            {
                std::unique_lock<boost::fibers::mutex> lock(mutex);
                condvar.wait_for(lock, std::chrono::milliseconds(50));
            }
            //emulate some calculations
            std::this_thread::sleep_for(std::chrono::milliseconds(5));
        }
    };

    boost::fibers::fiber fiber1(do_work);
    boost::fibers::fiber fiber2(do_work);
    boost::fibers::fiber fiber3(do_work);
    boost::fibers::fiber fiber4(do_work);
    boost::fibers::fiber fiber5(do_work);
    boost::fibers::fiber fiber6(do_work);

    boost::fibers::fiber fiber([&]()
    {
        while (true)
        {
            {
                std::lock_guard<boost::fibers::mutex> lock(mutex);
                condvar.notify_one();
            }
            boost::this_fiber::sleep_for(std::chrono::milliseconds(10));
        }
    });
    fiber.join();
    return 0;
}

Compiler msvc-14.0, windows 7.

fiber dump?

when I create a main fiber and join(), the program dump. why????

endless-loop in buffered_channel::try_value_pop()

I am calling try_value_pop() in the buffered channel and end up in an endless loop.

try_pop_: full=0 empty=0 capacity=1 closed=0 producers=0 consumers=0 consumer_idx_=0 slots_[0].cycle.load()=2

My guess is that idx is 0 in try_value_pop_(). diff is 1 (2-(idx+1)) and the loop reloads consumer_idx_ which is 0.

Do you have any ideas how I ended up here? Thanks in advance.

C++11 example for asio spawn

I tried to use the boost::fibers::asio::spawn while using c++11, but it failed to compile and I noticed the example is missing under cpp11 directory. Is there any example for the usage? Or is it not supported under c++11?

build instructions

Hey Oliver,

This seems like a really interesting project - I'm keen to try it out, but I'm afraid I'm not very familiar with the boost/jam build system - the obvious commands I've tried out don't seem to work so well.

It might make sense to add a few lines to the README indicating how to run bjam on the project (or a shell script that does the same), for those of us less gifted with boost :)

Thanks!

OS X Support

I'm trying to get boost fiber to work on OS 10.10.4. The first issue I had was the OS X version of Clang doesn't support thread_local for some reason. I was considering switching fiber over to boost thread local storage instead of using thread_local, but I figured I would just try just using GCC-5.1.0 and link with stdlibc++ instead.

Building boost modular and boost fiber was successful, and building the fiber example "simple.cpp" was also successful, but it fails with segmentation faults. Any idea what's going on?

Maybe I'll hack it to use boost thread local storage so the standard clang will work instead..

Fiber fails to build on macOS with 1.65 rc1

This is happens with

  • Boost 1.65 rc1
  • Xcode 8.3.3
  • Apple LLVM version 8.1.0 (clang-802.0.42)
libs/fiber/src/numa/pin_thread.cpp:25:10: warning: pin_thread() not supported [-W#pragma-messages]
# pragma message "pin_thread() not supported"
         ^
libs/fiber/src/numa/pin_thread.cpp:30:22: error: expected ';' after expression
    throw fiber_error{
                     ^
                     ;
libs/fiber/src/numa/pin_thread.cpp:30:11: error: use of undeclared identifier 'fiber_error'
    throw fiber_error{
          ^
libs/fiber/src/numa/pin_thread.cpp:32:54: error: expected ';' after expression
            "boost fiber: pin_thread() not supported" };
                                                     ^
                                                     ;
libs/fiber/src/numa/pin_thread.cpp:32:13: warning: expression result unused [-Wunused-value]
            "boost fiber: pin_thread() not supported" };
            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2 warnings and 3 errors generated.

    "clang++" -x c++ -std=c++14 -stdlib=libc++ -mmacosx-version-min=10.8 -g -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk -arch i386 -arch x86_64 -O3 -O3 -Wno-inline -Wall -DBOOST_ALL_NO_LIB=1 -DBOOST_DISABLE_ASSERTS -DBOOST_FIBERS_SOURCE -DBOOST_FILESYSTEM_STATIC_LINK=1 -DBOOST_SYSTEM_STATIC_LINK=1 -DNDEBUG -I"." -c -o "/Users/gjasny/Git/ExternalLibs/boost/_output/macosx/boost/bin.v2/libs/fiber/build/clang-darwin-4.2.1/release/address-model-32_64/link-static/threading-multi/numa/pin_thread.o" "libs/fiber/src/numa/pin_thread.cpp"

Failing to build static lib with GCC 4.8 and C++11

Compiling the newest Boost release (version 1.64.0) fails when trying to compile Boost.Fiber as static library with GCC 4.8 and -std=c++11.

This seems to be related to this issue with Boost.Context. The call to callcc is an ambiguous overload.

common.mkdir /home/jenkins/workspace/TEST_Boost_Build/gcc48/build/boost/boost/bin.v2/libs/fiber
common.mkdir /home/jenkins/workspace/TEST_Boost_Build/gcc48/build/boost/boost/bin.v2/libs/fiber/build
common.mkdir /home/jenkins/workspace/TEST_Boost_Build/gcc48/build/boost/boost/bin.v2/libs/fiber/build/gcc-4.8
common.mkdir /home/jenkins/workspace/TEST_Boost_Build/gcc48/build/boost/boost/bin.v2/libs/fiber/build/gcc-4.8/release
common.mkdir /home/jenkins/workspace/TEST_Boost_Build/gcc48/build/boost/boost/bin.v2/libs/fiber/build/gcc-4.8/release/link-static
common.mkdir /home/jenkins/workspace/TEST_Boost_Build/gcc48/build/boost/boost/bin.v2/libs/fiber/build/gcc-4.8/release/link-static/threading-multi
common.mkdir /home/jenkins/workspace/TEST_Boost_Build/gcc48/build/boost/boost/bin.v2/libs/fiber/build/gcc-4.8/release/link-static/threading-multi/algo
gcc.compile.c++ /home/jenkins/workspace/TEST_Boost_Build/gcc48/build/boost/boost/bin.v2/libs/fiber/build/gcc-4.8/release/link-static/threading-multi/algo/algorithm.o
gcc.compile.c++ /home/jenkins/workspace/TEST_Boost_Build/gcc48/build/boost/boost/bin.v2/libs/fiber/build/gcc-4.8/release/link-static/threading-multi/algo/round_robin.o
gcc.compile.c++ /home/jenkins/workspace/TEST_Boost_Build/gcc48/build/boost/boost/bin.v2/libs/fiber/build/gcc-4.8/release/link-static/threading-multi/algo/shared_work.o
gcc.compile.c++ /home/jenkins/workspace/TEST_Boost_Build/gcc48/build/boost/boost/bin.v2/libs/fiber/build/gcc-4.8/release/link-static/threading-multi/algo/work_stealing.o
gcc.compile.c++ /home/jenkins/workspace/TEST_Boost_Build/gcc48/build/boost/boost/bin.v2/libs/fiber/build/gcc-4.8/release/link-static/threading-multi/barrier.o
gcc.compile.c++ /home/jenkins/workspace/TEST_Boost_Build/gcc48/build/boost/boost/bin.v2/libs/fiber/build/gcc-4.8/release/link-static/threading-multi/condition_variable.o
gcc.compile.c++ /home/jenkins/workspace/TEST_Boost_Build/gcc48/build/boost/boost/bin.v2/libs/fiber/build/gcc-4.8/release/link-static/threading-multi/context.o
libs/fiber/src/context.cpp: In constructor ‘boost::fibers::context::context(boost::fibers::dispatcher_context_t, const boost::context::preallocated&, const default_stack&, boost::fibers::scheduler*)’:
libs/fiber/src/context.cpp:236:14: error: call of overloaded ‘callcc(const std::allocator_arg_t&, const boost::context::preallocated&, const default_stack&, boost::fibers::context::context(boost::fibers::dispatcher_context_t, const boost::context::preallocated&, const default_stack&, boost::fibers::scheduler*)::__lambda5)’ is ambiguous
             });
              ^
libs/fiber/src/context.cpp:236:14: note: candidates are:
In file included from ./boost/fiber/context.hpp:28:0,
                 from libs/fiber/src/context.cpp:7:
./boost/context/continuation.hpp:469:1: note: boost::context::continuation boost::context::callcc(std::allocator_arg_t, StackAlloc, Fn&&, Arg ...) [with StackAlloc = boost::context::preallocated; Fn = const boost::context::basic_fixedsize_stack<boost::context::stack_traits>&; Arg = {boost::fibers::context::context(boost::fibers::dispatcher_context_t, const boost::context::preallocated&, const default_stack&, boost::fibers::scheduler*)::__lambda5}]
 callcc( std::allocator_arg_t, StackAlloc salloc, Fn && fn, Arg ... arg) {
 ^
./boost/context/continuation.hpp:483:1: note: boost::context::continuation boost::context::callcc(std::allocator_arg_t, boost::context::preallocated, StackAlloc, Fn&&, Arg ...) [with StackAlloc = boost::context::basic_fixedsize_stack<boost::context::stack_traits>; Fn = boost::fibers::context::context(boost::fibers::dispatcher_context_t, const boost::context::preallocated&, const default_stack&, boost::fibers::scheduler*)::__lambda5; Arg = {}]
 callcc( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn, Arg ... arg) {
 ^
./boost/context/continuation.hpp:514:1: note: boost::context::continuation boost::context::callcc(std::allocator_arg_t, boost::context::preallocated, StackAlloc, Fn&&) [with StackAlloc = boost::context::basic_fixedsize_stack<boost::context::stack_traits>; Fn = boost::fibers::context::context(boost::fibers::dispatcher_context_t, const boost::context::preallocated&, const default_stack&, boost::fibers::scheduler*)::__lambda5]
 callcc( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn) {
 ^
./boost/context/continuation.hpp:457:1: note: boost::context::continuation boost::context::callcc(Fn&&, Arg ...) [with Fn = const std::allocator_arg_t&; Arg = {boost::context::preallocated, boost::context::basic_fixedsize_stack<boost::context::stack_traits>, boost::fibers::context::context(boost::fibers::dispatcher_context_t, const boost::context::preallocated&, const default_stack&, boost::fibers::scheduler*)::__lambda5}; <template-parameter-1-3> = void]
 callcc( Fn && fn, Arg ... arg) {
 ^

    "g++-4.8"  -ftemplate-depth-128 -O3 -finline-functions -Wno-inline -Wall -pthread -m64 -m64 -fpic  -std=c++11   -m64 -fpic    -DBOOST_ALL_NO_LIB=1 -DBOOST_DISABLE_ASSERTS -DBOOST_FIBERS_SOURCE -DNDEBUG  -I"." -c -o "/home/jenkins/workspace/TEST_Boost_Build/gcc48/build/boost/boost/bin.v2/libs/fiber/build/gcc-4.8/release/link-static/threading-multi/context.o" "libs/fiber/src/context.cpp"

...failed gcc.compile.c++ /home/jenkins/workspace/TEST_Boost_Build/gcc48/build/boost/boost/bin.v2/libs/fiber/build/gcc-4.8/release/link-static/threading-multi/context.o...

HTH,
Deniz Bahadir

PS: I reported this issue already for the beta releases of Boost 1.64.0 on the Boost mailing-list but it obviously got not much attention.

future and move only results

It's possible to use a future to return a move-only object?

This code doesn't compile (gcc 4.9.2 / clang 3.6) (fibers master branch)

#include <boost/fiber/all.hpp>
#include <iostream>

struct A {
    A() = default;
    A(A const&) = delete;
    A(A&&) = default;

    int value;
};

int main() {
    using namespace boost::fibers;

    promise<A> p;
    auto future = p.get_future();
    std::cout << future.get().value << std::endl;
}

gcc output (trimmed):

./support/deps/include/boost/fiber/future/future.hpp: In instantiation of ‘R boost::fibers::future<R>::get() [with R = A]’:
tests/c.cpp:17:29:   required from here
./support/deps/include/boost/fiber/future/future.hpp:80:25: error: use of deleted function ‘A::A(const A&)’
         return tmp->get();
                         ^
tests/c.cpp:6:5: note: declared here
     A(A const&) = delete;

Included header file from Boost.Context is missing.

I was trying to build Fiber for Boost 1.60.0 when the following error occurred.

In file included from libs/fiber/src/algorithm.cpp:9:0:
./boost/fiber/context.hpp:20:42: fatal error: boost/context/detail/apply.hpp: No such file or directory
compilation terminated.
It seems the header "boost/context/detail/apply.hpp" was removed from boost context.
Is this an issue for fiber?

Thank you.

Compile error on ARMv6

Some ARM processors do not support "yield" instruction used in include/boost/fiber/detail/cpu_relax.hpp.

Compilation with GCC will generate error messages such as:

/tmp/ccUV8Ii4.s: Assembler messages:
/tmp/ccUV8Ii4.s:2171: Error: selected processor does not support ARM mode `yield'

This problem will happen on Raspbian (-march=armv6) and Debian armel (-march=armv4t I believe) for example.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.