繁体   English   中英

将Boost.Coroutine与Boost.ASIO一起使用会引起断言

[英]Use of Boost.Coroutine with Boost.ASIO causes assertion

我有boost :: asio :: io_context在多个线程中运行(通过ctx.run()),我在boost.coroutines中使用了几个异步对象,这些对象通过boost :: asio :: spawn运行。 我有以下断言:

Assertion failed: ! is_running(), file C:\boost\boost_1_68_0\msvc_x86\include\boost-1_68\boost\coroutine\detail\push_coroutine_impl.hpp, line 258

我正在提供一个导致相同错误的最小示例。 请帮帮我:我在做什么错?

Boost版本是1.68

[更新]:代码中有一个修复程序(忘记锁定io_context),但是无论如何它不会影响断言。

#include <iostream>
#include <thread>
#include <boost/asio.hpp>
#include <boost/asio/spawn.hpp>

template<class CompletionToken>
BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void(boost::system::error_code))
asyncDo(boost::asio::io_context& ctx, CompletionToken&& token)
{
    using CompletionType = boost::asio::async_completion<CompletionToken, void(boost::system::error_code)>;
    CompletionType completion{ token };
    ctx.post(
        [handler{ completion.completion_handler }](){
            using boost::asio::asio_handler_invoke;
            asio_handler_invoke(std::bind(handler, boost::system::error_code()), &handler);
            return;
        });
    return completion.result.get();
}

void coroFunc(boost::asio::io_context& ctx, boost::asio::yield_context yield)
{
    for (;;) {
        std::cerr << std::this_thread::get_id() << '\n';
        asyncDo(ctx, yield);
        std::cerr << std::this_thread::get_id() << '\n';
    }
}

int main(int, char* [])
{
    boost::asio::io_context ctx;
    boost::asio::executor_work_guard<boost::asio::io_context::executor_type> work(ctx.get_executor());

    boost::asio::spawn(ctx, std::bind(coroFunc, std::ref(ctx), std::placeholders::_1));

    std::thread([&ctx]() { ctx.run(); }).detach();
    std::thread([&ctx]() { ctx.run(); }).detach();

    std::cin.get();
    work.reset();

    return 0;
}

经过数小时的谷歌搜索和尝试,我找到了适合我的解决方案(至少在我的测试中)。 主要思想是将发布到ctx替换为发布到关联的执行者

    auto executor = boost::asio::get_associated_executor(completion.completion_handler, ctx);
    auto allocator = boost::asio::get_associated_allocator(completion.completion_handler);

    executor.post(
        [handler = HandlerType{ std::move(completion.completion_handler) }](){
            using boost::asio::asio_handler_invoke;
            asio_handler_invoke(std::bind(handler, boost::system::error_code()), &handler);
            return;
        },
        allocator);

整个代码:

#include <iostream>
#include <stdexcept>
#include <thread>
#include <boost/asio.hpp>
#include <boost/asio/spawn.hpp>


template<class CompletionToken>
BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void(boost::system::error_code))
asyncDo(boost::asio::io_context& ctx, CompletionToken&& token)
{
    using CompletionType = boost::asio::async_completion<CompletionToken, void(boost::system::error_code)>;
    using HandlerType = typename CompletionType::completion_handler_type;
    CompletionType completion{ token };

    auto executor = boost::asio::get_associated_executor(completion.completion_handler, ctx);
    auto allocator = boost::asio::get_associated_allocator(completion.completion_handler);

    executor.post(
        [handler = HandlerType{ std::move(completion.completion_handler) }](){
            using boost::asio::asio_handler_invoke;
            asio_handler_invoke(std::bind(handler, boost::system::error_code()), &handler);
            return;
        },
        allocator);

    return completion.result.get();
}

void coroFunc(boost::asio::io_context& ctx, boost::asio::yield_context yield)
{
    for (;;) {
        try {
            std::cerr << "(0): " << std::this_thread::get_id() << '\n';
            asyncDo(ctx, yield);
            std::cerr << "(1): " << std::this_thread::get_id() << '\n';
        } catch (std::exception const& e) {
            std::cerr << "e: " << e.what() << '\n';
        }
    }
}

int main(int, char* [])
{
    boost::asio::io_context ctx;
    boost::asio::executor_work_guard<boost::asio::io_context::executor_type> work(ctx.get_executor());

    boost::asio::spawn(ctx, std::bind(coroFunc, std::ref(ctx), std::placeholders::_1));

    std::thread([&ctx]() {
        for (;;) {
            try {
                ctx.run();
                break;
            } catch (std::exception const& e) {
                std::cerr << "e: " << e.what() << '\n';
            }
        }
    }).detach();
    std::thread([&ctx]() {
        for (;;) {
            try {
                ctx.run();
                break;
            } catch (std::exception const& e) {
                std::cerr << "e: " << e.what() << '\n';
            }
        }
    }).detach();

    std::cin.get();
    work.reset();

    return 0;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM