...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
If a worker thread is used but no fiber is created or parts of the framework
(like this_fiber::yield()
) are touched, then no fiber scheduler
is instantiated.
auto worker = std::thread( []{ // fiber scheduler not instantiated }); worker.join();
If use_scheduling_algorithm<>() is invoked, the fiber scheduler is created. If the worker thread simply returns, destroys the scheduler and terminates.
auto worker = std::thread( []{ // fiber scheduler created boost::fibers::use_scheduling_algorithm<my_fiber_scheduler>(); }); worker.join();
In order to keep the worker thread running, the fiber associated with the thread
stack (which is called “main” fiber) is blocked. For instance
the “main” fiber might wait on a condition_variable
.
For a gracefully shutdown condition_variable
is signalled
and the “main” fiber returns. The scheduler gets destructed if
all fibers of the worker thread have been terminated.
boost::fibers::mutex mtx; boost::fibers::condition_variable_any cv; auto worker = std::thread( [&mtx,&cv]{ mtx.lock(); // suspend till signalled cv.wait(mtx); mtx.unlock(); }); // signal termination cv.notify_all(); worker.join();
Tasks can be transferred via channels. The worker thread runs a pool of fibers that dequeue and executed tasks from the channel. The termination is signalled via closing the channel.
using task = std::function<void()>; boost::fibers::buffered_channel<task> ch{1024}; auto worker = std::thread( [&ch]{ // create pool of fibers for (int i=0; i<10; ++i) { boost::fibers::fiber{ [&ch]{ task tsk; // dequeue and process tasks while (boost::fibers::channel_op_status::closed!=ch.pop(tsk)){ tsk(); } }}.detach(); } task tsk; // dequeue and process tasks while (boost::fibers::channel_op_status::closed!=ch.pop(tsk)){ tsk(); } }); // feed channel with tasks ch.push([]{ ... }); ... // signal termination ch.close(); worker.join();
An alternative is to use a work-stealing scheduler. This kind of scheduling algorithm a worker thread steals fibers from the ready-queue of other worker threads if its own ready-queue is empty.
Note | |
---|---|
Wait till all worker threads have registered the work-stealing scheduling algorithm. |
barrier b{2}; boost::fibers::use_scheduling_algorithm<boost::fibers::algo::work_stealing>(2); boost::fibers::mutex mtx; boost::fibers::condition_variable_any cv; auto worker = std::thread( [&mtx,&cv,&b]{ boost::fibers::use_scheduling_algorithm<boost::fibers::algo::work_stealing>(2); // wait till all threads joining the work stealing have been registered b.wait(); mtx.lock(); // suspend main-fiber from the worker thread cv.wait(mtx); mtx.unlock(); }); // wait till all threads have been registered the scheduling algorithm b.wait(); // create fibers with tasks boost::fibers::fiber f{[]{ ... }}; ... // signal termination cv.notify_all(); worker.join();
Important | |
---|---|
Because the TIB (thread information block on Windows) is not fully described in the MSDN, it might be possible that not all required TIB-parts are swapped. Using WinFiber implementation might be an alternative (see documentation about implementations fcontext_t, ucontext_t and WinFiber of boost.context). |