boost::asio-signal_set处理程序仅在捕获第一个信号后执行,并忽略相同类型的连续信号

boost::asio signal_set handler only executes after first signal is caught and ignores consecutive signals of the same type

本文关键字:信号 执行 连续 同类型 第一个 处理 set asio-signal 程序 boost      更新时间:2023-10-16

我有一个程序,希望通过发送SIGINT来停止它,以便将一些数据写入文件,而不是立即退出。但是,如果程序的用户再次发送SIGINT,则程序应立即退出,并忘记将数据写入文件。

出于可移植性的原因,我想使用boost::asio来实现此目的。

我最初的(简化的)方法(见下文)不起作用。这是不可能的,还是我错过了什么?

处理程序似乎只被调用一次(打印出消息),并且当循环达到最大迭代次数时,程序总是停止。

void handler(
const boost::system::error_code& error,
int signal_number) {
    if (!error) {
        static bool first = true;
        if(first) {
            std::cout << " A signal(SIGINT) occurred." << std::endl;
            // do something like writing data to a file
            first = false;
        }
        else {
            std::cout << " A signal(SIGINT) occurred, exiting...." << std::endl;
            exit(0);
        }
    }
}
int main() {
    // Construct a signal set registered for process termination.
    boost::asio::io_service io;
    boost::asio::signal_set signals(io, SIGINT);
    // Start an asynchronous wait for one of the signals to occur.
    signals.async_wait(handler);
    io.run();
    size_t i;
    for(i=0;i<std::numeric_limits<size_t>::max();++i){
        // time stepping loop, do some computations
    }
    std::cout << i << std::endl;
    return 0;
}

当您的第一个事件被处理时,您不会在服务对象上发布任何新的工作,因此它会退出。

这意味着(在ioservice退出之后)将启动紧密循环。这可能不是你所期望的。

  1. 如果你想再次监听SIGINT,你必须等待处理程序再次设置的信号:

    #include <boost/asio.hpp>
    #include <boost/asio/signal_set.hpp>
    #include <boost/bind.hpp>
    #include <boost/atomic.hpp>
    #include <iostream>
    void handler(boost::asio::signal_set& this_, boost::system::error_code error, int signal_number) {
        if (!error) {
            static boost::atomic_bool first(true);
            if(first) {
                // do something like writing data to a file
                std::cout << " A signal(SIGINT) occurred." << std::endl;
                first = false;
                this_.async_wait(boost::bind(handler, boost::ref(this_), _1, _2));
            }
            else {
                std::cout << " A second signal(SIGINT) occurred, exiting...." << std::endl;
                exit(1);
            }
        }
    }
    int main() {
        // Construct a signal set registered for process termination.
        boost::asio::io_service io;
        boost::asio::signal_set signals(io, SIGINT);
        // Start an asynchronous wait for one of the signals to occur.
        signals.async_wait(boost::bind(handler, boost::ref(signals), _1, _2));
        io.run();
        return 2;
    }
    

    正如您所看到的,我将signal_set&引用绑定到处理程序,以便在接收到第一个信号后能够对其进行async_wait。此外,原则上,我将first作为原子(尽管在多个线程上运行io_service之前,这是不必要的)。

  2. 你真的想在后台运行io_service吗?在这种情况下,让它看起来像这样:

    signals.async_wait(boost::bind(handler, boost::ref(signals), _1, _2));
    boost::thread(boost::bind(&boost::asio::io_service::run, boost::ref(io))).detach();
    while (true)
    {
        std::cout << "Some work on the main thread...n";
        boost::this_thread::sleep_for(boost::chrono::seconds(1));
    }
    

    典型输出:

    Some work on the main thread...
    Some work on the main thread...
    Some work on the main thread...
    ^CSome work on the main thread...
     A signal(SIGINT) occurred.
    Some work on the main thread...
    Some work on the main thread...
    ^CSome work on the main thread...
     A second signal(SIGINT) occurred, exiting....