Производитель / Потребитель, использующий Boost.Fibers

Я пытаюсь создать производителя / потребителя с помощью Boost.Fibers. Похоже на использование channels из этого примера - это правильно. Пример необходимо немного изменить, так как я хочу сигнализировать о завершении с помощью promise/future. Итак, я написал какой-то наивный код, чтобы ничего не делать, просто сигнализировал о завершении.

struct fiber_worker {
    fiber_worker() {
        wthread = std::thread([self{this}]() {
            for (int i = 0; i < 4; ++i) {
                boost::fibers::fiber{
                        [self]() {
                            task tsk;
                            while (boost::fibers::channel_op_status::closed != self->ch.pop(tsk)) {
                                tsk();
                            }
                        }}.detach();
            }
            task tsk;
            while (boost::fibers::channel_op_status::closed != self->ch.pop(tsk)) {
                tsk();
            }
        });
    }

    boost::fibers::future<void> submit() noexcept {
        boost::fibers::promise<void> prom;
        auto retVal = prom.get_future();
        ch.push([p{std::move(prom)}]() mutable { p.set_value(); });
        return retVal;
    }

    ~fiber_worker() {
        ch.close();
        wthread.join();
    }

    using task = std::function<void()>;
    std::thread wthread;
    boost::fibers::buffered_channel<task> ch{1024};
};

Однако он не будет компилироваться, он будет жаловаться на promise доступ к удаленному конструктору копии. Прежде всего, я не понимаю, где (и почему) вызывается конструктор копирования. Во-вторых, я не уверен, что именно так следует использовать boost::fibers.
Использование

int main() {
        fiber_worker bwk;
        bwk.submit().get();
}

Сообщение об ошибке

В файле, включенном из / usr / include / c ++ / 7 / future: 48: 0, из /home/user/Downloads/boostchannels66_0/boost/fiber/exceptions.hpp:12, из / home / user / Downloads / boostchannels66_0 / boost /fiber/future/future.hpp:17, из /home/user/Development/Tests/shared_state_test/main.cpp:4: /usr/include/c++/7/bits/std_function.h: при создании экземпляра static void std :: _ Function_base :: _ Base_manager ‹_Functor> :: _ M_clone (std :: _ Any_data &, const std :: _ Any_data &, std :: false_type) [с _Functor = fiber_worker :: submit () ::; std :: false_type = std :: integration_constant] ': /usr/include/c++/7/bits/std_function.h:227:16: требуется от' static bool std :: _ Function_base :: _ Base_manager ‹_Functor> :: _ M_manager ( std :: _ Any_data &, const std :: _ Any_data &, std :: _ Manager_operation) [with _Functor = fiber_worker :: submit () ::] '/usr/include/c++/7/bits/std_function.h:695:19: требуется from 'std :: function ‹_Res (_ArgTypes ...)> :: function (_Functor) [с _Functor = fiber_worker :: submit () ::; = пусто; = пусто; _Res = void; _ArgTypes = {}] '/home/user/Development/Tests/shared_state_test/main.cpp:45:66: здесь требуется
/usr/include/c++/7/bits/std_function.h:192:6: ошибка: использование удаленной функции 'fiber_worker :: submit () ::: :( const fiber_worker :: submit () :: &)' new _Functor (__source._M_access ‹_Functor> ()); ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ / home / user /Development/Tests/shared_state_test/main.cpp:45:36: note: 'fiber_worker :: submit () ::: :( const fiber_worker :: submit () :: &)' неявно удаляется, потому что определение по умолчанию будет неправильно сформированный: ch.push (p {std :: move (prom)} mutable {p.set_value ();}); ^ /home/user/Development/Tests/shared_state_test/main.cpp:45:36: ошибка: использование удаленной функции 'boost :: fibres :: обещание :: обещание (const boost :: волокна :: обещание &)' в файле включено из /home/user/Development/Tests/shared_state_test/main.cpp:5:0: /home/user/Downloads/boostchannels66_0/boost/fiber/future/promise.hpp:192:5: note: здесь объявлено обещание ( обещание const &) = удалить; ^ ~~~~~~

EDIT001: похоже, что канал не может использовать движущиеся лямбды

struct test {
    test() = default;

    test(const test &rhs) = delete;

    test &operator=(const test &rhs)= delete;

    test(test &&rhs) = default;

    test &operator=(test &&rhs)= default;

    size_t _1 = 0;
    size_t _2 = 0;
    size_t _3 = 0;
    size_t _4 = 0;

    void print() const {
        std::cout << _1 << _2 << _3 << 4 << std::endl;
    }
};

int main() {
    using task = std::function<void()>;
    boost::fibers::buffered_channel<task> ch{1024};
    test tst;
    ch.push([t{std::move(tst)}]() { t.print(); });
}

Свяжется с Boost :: Fibre Maintering для уточнения

EDIT002: Нет проблем с boost::fibers::buffered_channel, единственная проблема здесь с моим Альцгеймером, я (снова) забыл, что std::function должен быть копируемым, и когда лямбда захватывает только подвижный тип, создание std::function не удастся при копировании


person kreuzerkrieg    schedule 15.04.2018    source источник
comment
Канал явно требует, чтобы задачи были копируемыми.   -  person sehe    schedule 15.04.2018
comment
Ага, уже понял. Я забыл (снова), что std :: function должен быть копируемым и копируемым   -  person kreuzerkrieg    schedule 15.04.2018
comment
@sehe, BTW, boost::fibers::unbuffered_channel может принимать объекты только для перемещения, почему buffered one не может? особенно когда buffered push может принимать lvalue?   -  person kreuzerkrieg    schedule 24.04.2018


Ответы (1)


Я считаю, что проблема не в том, что небуферизованный канал не может передавать подвижные элементы (одна из перегрузок push принимает T &&), а в том, что они должны быть сконструированы по умолчанию, чтобы можно было предварительно заполнить очередь элементами для переместите перемещенный элемент в.

person randian    schedule 08.10.2019