boost :: волоконно-оптическое планирование - когда и как - PullRequest
0 голосов
/ 25 июня 2018

Согласно документации

текущее работающее волокно сохраняет контроль, пока не вызовет операция, передающая управление менеджеру

Я могу думать только об одной операции - boost::this_fiber::yield, которая может привести к переключению управления с волокна на волокно. Тем не менее, когда я запускаю что-то вроде

bf::fiber([](){std::cout << "Bang!" << std::endl;}).detach();
bf::fiber([](){std::cout << "Bung!" << std::endl;}).detach();

Я получаю вывод как

Взрыв! Bung!
\ п
\ п

Это означает, что управление было передано между операторами << от одного волокна к другому. Как это могло случиться? Зачем? Каково общее определение управления передачей от волокна к волокну в контексте библиотеки boost::fiber?

EDIT001: Не могу уйти без кода:

#include <boost/fiber/fiber.hpp>
#include <boost/fiber/mutex.hpp>
#include <boost/fiber/barrier.hpp>
#include <boost/fiber/algo/algorithm.hpp>
#include <boost/fiber/algo/work_stealing.hpp>

namespace bf = boost::fibers;

class GreenExecutor
{
    std::thread worker;
    bf::condition_variable_any cv;
    bf::mutex mtx;
    bf::barrier barrier;
public:
    GreenExecutor() : barrier {2}
    {
        bf::use_scheduling_algorithm<bf::algo::work_stealing>(2);

        worker = std::thread([this] {
            bf::use_scheduling_algorithm<bf::algo::work_stealing>(2);
            // wait till all threads joining the work stealing have been registered
            barrier.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
        barrier.wait();
    }

    template<typename T>
    void PostWork(T&& functor)
    {
        bf::fiber {std::move(functor)}.detach();
    }

    ~GreenExecutor()
    {
        cv.notify_all();
        worker.join();
    }
};

int main()
{
    GreenExecutor executor;
    std::this_thread::sleep_for(std::chrono::seconds(1));
    int i = 0;
    for (auto j = 0ul; j < 10; ++j) {
        executor.PostWork([idx {++i}]() {
            auto res = pow(sqrt(sin(cos(tan(idx)))), M_1_PI);
            std::cout << idx << " - " << res << std::endl;
        });
    }
    while (true) {
        boost::this_fiber::yield();
    }
    return 0;
}

выход

2 - 1 - -nan
0,503334 3 - 4 - 0,861055
0,971884 5 - 6 - 0,968536
-нан 7 - 8 - 0,921959
0.9580699
- 10 - 0,948075
0.961811

1 Ответ

0 голосов
/ 27 июня 2018

Хорошо, было несколько вещей, которые я пропустил, во-первых, мой вывод был основан на непонимании того, как все работает в boost::fiber
Строка в конструкторе, упомянутая в вопросе bf::use_scheduling_algorithm<bf::algo::work_stealing>(2);
, была установленапланировщик в потоке, в котором был создан экземпляр GreenExecutor (в основном потоке), поэтому при запуске двух рабочих fiber s я фактически инициировал два потока, которые будут обрабатывать отправленные fiber s, которые, в свою очередь, обрабатывали быони fibers асинхронно, таким образом смешивая вывод std::cout.Никакой магии, все работает как положено, boost::fiber::yield по-прежнему является единственной возможностью передать управление от одного волокна к другому

...