boost_asio_handler_invoke_helpers :: invoke仍然是在boost asio 1.70中调用完成处理程序的受支持方法吗?

时间:2019-08-08 05:12:52

标签: c++ boost-asio

我正在使用asio将代码从boost 1.65.1迁移到1.70.0。 有一个使用boost_asio_handler_invoke_helpers :: invoke的代码,它似乎不能像以前的版本那样工作。

我在github上发现了此问题https://github.com/boostorg/asio/issues/79,解释了executor_binder的工作方式。因此,看来旧的asio_handler_invoke函数在这种情况下将不再起作用。

class callback_service {
public:
    void run() {
        if (callback_) callback_();
    }

    void subscribe(std::function<void(void)> callback) {
        callback_ = std::move(callback);
    }

private:
    std::function<void(void)> callback_;
};

template <typename CompletionToken>
auto async_wait_callback(callback_service& service, CompletionToken&& token)
{
    return boost::asio::async_initiate<CompletionToken, void(void)>(
        [] (auto&& completion_handler, callback_service& s) {
            s.subscribe([h=std::move(completion_handler)] () mutable {

                // Is this still worked in 1.70 ?
                boost_asio_handler_invoke_helpers::invoke(h, h);
            });
        },
        token, std::ref(service));
}

BOOST_AUTO_TEST_CASE(test_async_wait_callback)
{
    boost::asio::io_context ioc;
    auto work = boost::asio::make_work_guard(ioc);

    callback_service service;

    boost::asio::spawn(ioc, [&] (boost::asio::yield_context yield) {
        const auto initiate_thread_id = std::this_thread::get_id();

        boost::asio::post(ioc, [&] {
            // call the completion handler from another thread.
            std::thread t([&] {
                service.run();
            });
            t.join();
        });

        async_wait_callback(service, yield);

        // Check if we resume in the correct execution context.
        BOOST_CHECK_EQUAL(initiate_thread_id, std::this_thread::get_id());
        ioc.stop();
    });

    ioc.run();
}

测试代码失败,并显示此错误

Running 1 test case...
error: in "test_async_wait_callback": check initiate_thread_id == std::this_thread::get_id() has failed [10912 != 26444]

这意味着没有在正确的执行上下文中恢复堆栈式协程。

1 个答案:

答案 0 :(得分:0)

我当前的解决方法是通过get_associated_executor调度旧的回调。

template <typename CompletionToken>
auto async_wait_callback(callback_service& service, CompletionToken&& token)
{
    return boost::asio::async_initiate<CompletionToken, void(void)>(
        [] (auto&& completion_handler, callback_service& s) {
            s.subscribe([h=std::move(completion_handler)] () mutable {
                auto ex = boost::asio::get_associated_executor(h);
                boost::asio::dispatch(ex, [h=std::move(h)] () mutable {
                   boost_asio_handler_invoke_helpers::invoke(h, h);
                });
            });
        },
        token, std::ref(service));
}