1[/ 2 Copyright Oliver Kowalke 2017. 3 Distributed under the Boost Software License, Version 1.0. 4 (See accompanying file LICENSE_1_0.txt or copy at 5 http://www.boost.org/LICENSE_1_0.txt 6] 7 8[#worker] 9[section:worker Running with worker threads] 10 11[heading Keep workers running] 12 13If a worker thread is used but no fiber is created or parts of the framework 14(like __yield__) are touched, then no fiber scheduler is instantiated. 15 16 auto worker = std::thread( 17 []{ 18 // fiber scheduler not instantiated 19 }); 20 worker.join(); 21 22 23If ['use_scheduling_algorithm<>()] is invoked, the fiber scheduler is created. 24If the worker thread simply returns, destroys the scheduler and terminates. 25 26 auto worker = std::thread( 27 []{ 28 // fiber scheduler created 29 boost::fibers::use_scheduling_algorithm<my_fiber_scheduler>(); 30 }); 31 worker.join(); 32 33 34In order to keep the worker thread running, the fiber associated with the thread 35stack (which is called ["main] fiber) is blocked. For instance the ["main] fiber 36might wait on a __condition__. For a gracefully shutdown __condition__ is 37signalled and the ["main] fiber returns. The scheduler gets destructed if all 38fibers of the worker thread have been terminated. 39 40 boost::fibers::mutex mtx; 41 boost::fibers::condition_variable_any cv; 42 auto worker = std::thread( 43 [&mtx,&cv]{ 44 mtx.lock(); 45 // suspend till signalled 46 cv.wait(mtx); 47 mtx.unlock(); 48 }); 49 // signal termination 50 cv.notify_all(); 51 worker.join(); 52 53 54[heading Processing tasks] 55 56Tasks can be transferred via channels. The worker thread runs a pool of fibers 57that dequeue and executed tasks from the channel. The termination is signalled via 58closing the channel. 59 60 using task = std::function<void()>; 61 boost::fibers::buffered_channel<task> ch{1024}; 62 auto worker = std::thread( 63 [&ch]{ 64 // create pool of fibers 65 for (int i=0; i<10; ++i) { 66 boost::fibers::fiber{ 67 [&ch]{ 68 task tsk; 69 // dequeue and process tasks 70 while (boost::fibers::channel_op_status::closed!=ch.pop(tsk)){ 71 tsk(); 72 } 73 }}.detach(); 74 } 75 task tsk; 76 // dequeue and process tasks 77 while (boost::fibers::channel_op_status::closed!=ch.pop(tsk)){ 78 tsk(); 79 } 80 }); 81 // feed channel with tasks 82 ch.push([]{ ... }); 83 ... 84 // signal termination 85 ch.close(); 86 worker.join(); 87 88 89An alternative is to use a work-stealing scheduler. This kind of scheduling 90algorithm a worker thread steals fibers from the ready-queue of other worker 91threads if its own ready-queue is empty. 92 93[note Wait till all worker threads have registered the work-stealing scheduling 94algorithm.] 95 96 boost::fibers::mutex mtx; 97 boost::fibers::condition_variable_any cv; 98 // start wotrker-thread first 99 auto worker = std::thread( 100 [&mtx,&cv]{ 101 boost::fibers::use_scheduling_algorithm<boost::fibers::algo::work_stealing>(2); 102 mtx.lock(); 103 // suspend main-fiber from the worker thread 104 cv.wait(mtx); 105 mtx.unlock(); 106 }); 107 boost::fibers::use_scheduling_algorithm<boost::fibers::algo::work_stealing>(2); 108 // create fibers with tasks 109 boost::fibers::fiber f{[]{ ... }}; 110 ... 111 // signal termination 112 cv.notify_all(); 113 worker.join(); 114 115 116[important Because the TIB (thread information block on Windows) is not fully 117described in the MSDN, it might be possible that not all required TIB-parts are 118swapped. Using WinFiber implementation might be an alternative (see documentation 119about [@http://www.boost.org/doc/libs/1_65_1/libs/context/doc/html/context/cc/implementations__fcontext_t__ucontext_t_and_winfiber.html 120['implementations fcontext_t, ucontext_t and WinFiber of boost.context]]).] 121 122 123[endsect] 124