提升不保持io_service运行的asio处理程序

时间:2017-08-14 13:01:45

标签: c++ boost-asio

我想在我的boost io_service中添加一个信号处理程序,允许应用程序在用户按下Ctrl-C时干净地关闭。这当然可以通过停止循环轻松完成,如下所示:

boost::asio::io_service service;
boost::asio::signal_set signals{ service, SIGINT, SIGTERM };

signals.async_wait(std::bind(&boost::asio::io_service::stop, &service));

这会正常停止循环,允许析构函数执行常规清理行为。

问题是,一旦应用程序停止工作,它就不会停止,因为信号处理程序仍然注册了一个处理程序,因此io_service永远不会停止运行。

我还没有找到一个干净的方法。我当然可以自己进行信号处理,然后停止循环,但这种方式违背了使用boost(可移植性)的想法。

2 个答案:

答案 0 :(得分:0)

在以下代码中,http_server有一个"侦听套接字"接受多个连接。侦听套接字不断运行async_accept,因此io_service永远不会失效。 http_server.shutdown()函数关闭了侦听套接字和所有打开的连接,因此io_service不再有工作并停止运行:

void handle_stop(ASIO_ERROR_CODE const&, // error,
                 int, // signal_number,
                 http_server_type& http_server)
{
  std::cout << "Shutting down" << std::endl;
  http_server.shutdown();
}

...

ASIO::io_service io_service;
http_server_type http_server(io_service);

...


// The signal set is used to register termination notifications
ASIO::signal_set signals_(io_service);
signals_.add(SIGINT);
signals_.add(SIGTERM);
#if defined(SIGQUIT)
signals_.add(SIGQUIT);
#endif // #if defined(SIGQUIT)

// register the handle_stop callback
signals_.async_wait([&http_server]
  (ASIO_ERROR_CODE const& error, int signal_number)
{ handle_stop(error, signal_number, http_server); });

...

io_service.run();
std::cout << "io_service.run complete, shutdown successful" << std::endl;

此方法也适用于线程池,请参阅:thread_pool_http_server.cpp

答案 1 :(得分:0)

我可能会为此而下地狱,但我找到了一个解决方法来获得一个不会影响正在运行的处理程序数量的处理程序。它严重滥用了work_guard boost提供的功能,手动调用析构函数并且错误地使用了新的位置,但它确实有效。

#pragma once

#include <boost/asio/io_service.hpp>
#include <utility>
#include <memory>

template <typename HANDLER>
class unwork
{
    public:
        unwork(boost::asio::io_service &service, HANDLER &&handler) :
            _work_guard(std::make_unique<boost::asio::io_service::work>(service)),
            _handler(std::forward<HANDLER>(handler))
        {
            // wait for the handler to be installed
            service.post([work_guard = _work_guard.operator->()]() {
                // remove the work guard and the handler that has now been installed
                work_guard->~work();
                work_guard->~work();
            });
        }

        unwork(const unwork &that) :
            unwork(that._work_guard->get_io_service(), that._handler)
        {}

        unwork(unwork &&that) :
            _work_guard(std::move(that._work_guard)),
            _handler(std::move(that._handler))
        {}

        ~unwork()
        {
            // was the work guard not moved out?
            if (_work_guard) {
                // add the work guard reference and the handler reference again
                new (_work_guard.operator->()) boost::asio::io_service::work{ _work_guard->get_io_service() };
                new (_work_guard.operator->()) boost::asio::io_service::work{ _work_guard->get_io_service() };
            }
        }

        template <class ...Arguments>
        auto operator()(Arguments ...parameters)
        {
            return _handler(std::forward<Arguments>(parameters)...);
        }
    private:
        std::unique_ptr<boost::asio::io_service::work>  _work_guard;
        HANDLER                                         _handler;
};

// maker function, for c++ < c++17
template <typename HANDLER>
unwork<HANDLER> make_unwork(boost::asio::io_service &service, HANDLER &&handler)
{
    // create the new unwork wrapper
    return { service, std::forward<HANDLER>(handler) };
}

如果您正在使用c ++ 14,则通过将处理程序包装在make_unwork()调用中来使用它。在c ++ 17中,构造函数可以直接使用。