有没有一种方法可以明确销毁在给定boost :: asio :: io_context上所有待处理的处理程序?

时间:2018-09-03 09:13:54

标签: c++ boost-asio

据我所知,就我检查boost :: asio文档和源代码而言,除了销毁上下文本身之外,没有其他方法可以明确销毁给定io_context上的所有挂起处理程序?

如果可能的话,我需要能够停止io_context,销毁io_context上待处理的处理程序,然后做一些其他事情,最后销毁与给定io_context和关联的所有io对象(计时器,管道等)。 io_context本身。

我知道我可以使用work_guard :: reset并让所有挂起的处理程序运行,然后io_context会自行停止,但是问题是许多处理程序可能会产生(发布/延迟/等)新的挂起处理程序等,例如,每个此类处理程序都需要使用“如果已停止”之类的保护措施。

我认为io_context :: shutdown确实可以做到这一点,但是除了继承之外,没有办法明确地调用shutdown函数,因为它不是公共的。

谢谢。

1 个答案:

答案 0 :(得分:0)

使用受保护的shutdown尝试您的建议会导致我的系统出现段错误。我认为它受到保护是有原因的:)

无论如何,restart / stop / reset的明智组合似乎可以胜任。奇怪的是,某些处理程序队列显然停留在周围,除非执行(空)run / run_one。实际上,即使一个poll_one似乎也足够。因此,请务必包括在内。

这是我的测试平台代码,您可能会发现它很有用:

Live On Coliru

#include <boost/asio.hpp>
#include <iostream>
using namespace std::chrono_literals;

struct Handler {
    void operator()(boost::system::error_code ec) { std::cout << "Handler invoked: " << ec.message() << std::endl; }

    struct Instance { // logging only unique instance to avoid noise of moved handlers
        Instance()  { std::cout << "Created handler instance"   << std::endl; }
        ~Instance() { std::cout << "Destroyed handler instance" << std::endl; }
    };
    std::unique_ptr<Instance> _instance = std::make_unique<Instance>();
};

int main()
{
    struct Hack : boost::asio::io_context { 
        using boost::asio::io_context::shutdown;
    } io;
    auto work = make_work_guard(io);

    std::cout << " -- run" << std::endl;
    auto t = std::thread([&]{ io.run(); });

    {
        boost::asio::high_resolution_timer tim(io, 2s);
        tim.async_wait(Handler{});
        work.reset(); // no longer needed

        std::this_thread::sleep_for(500ms);

#if 1
        io.stop();
#else
        io.shutdown(); // segfaults
#endif
    }

    std::cout << " -- timer destructed" << std::endl;
    std::cout << " -- joining" << std::endl;
    t.join();

    std::cout << " -- empy run to flush handler queue" << std::endl;
    io.reset();
    //io.run();
    //io.run_one();
    io.poll_one();

    std::cout << " -- bye" << std::endl;
}

打印

 -- run
Created handler instance
 -- timer destructed
 -- joining
 -- empy run to flush handler queue
Handler invoked: Operation canceled
Destroyed handler instance
 -- bye

更新

这是我最好的建议(除了not sharing io外):

Live On Coliru

#include <boost/asio.hpp>
#include <iostream>
using namespace std::chrono_literals;

struct Handler {
    void operator()(boost::system::error_code ec) { std::cout << "Handler invoked: " << ec.message() << std::endl; }

    struct Instance { // logging only unique instance to avoid noise of moved handlers
        Instance()  { std::cout << "Created handler instance"   << std::endl; }
        ~Instance() { std::cout << "Destroyed handler instance" << std::endl; }
    };
    std::unique_ptr<Instance> _instance = std::make_unique<Instance>();
};

int main()
{
    std::unique_ptr<boost::asio::io_context> io;

    int i = 1;
    for (auto delay : { 1500ms, 500ms }) {
        std::cout << " ------------------- reinitialized -------------- \n";
        io = std::make_unique<boost::asio::io_context>();
        boost::asio::high_resolution_timer tim(*io, 1s);

        std::cout << i << " -- run" << std::endl;
        auto t = std::thread([&]{ io->run(); });

        tim.async_wait(Handler{});

        std::this_thread::sleep_for(delay);

        std::cout << i << " -- stop" << std::endl;
        io->stop();

        std::cout << i << " -- joining" << std::endl;
        t.join();

        std::cout << " ------------------- destruct ------------------- \n";
        io.reset();
    }

    std::cout << "Bye" << std::endl;
}

打印

 ------------------- reinitialized -------------- 
1 -- run
Created handler instance
Handler invoked: Success
Destroyed handler instance
1 -- stop
1 -- joining
 ------------------- destruct ------------------- 
 ------------------- reinitialized -------------- 
1 -- run
Created handler instance
1 -- stop
1 -- joining
 ------------------- destruct ------------------- 
Destroyed handler instance
Bye