2014-08-27 77 views
2

所以我有一个守护进程可以使用SIGQUIT正常关闭。 这个守护进程正在运行boost::asio::io_service。我用boost::asio::signal_set来捕捉这个信号。boost :: asio :: signal_set不会恢复之前的信号处理程序

我遇到了一个我认为完全错误的行为。当我销毁boost::asio::signal_set对象时,它不会恢复该信号的以前处理程序。 SIGQUIT的以前的处理程序是无操作的。所以在boost::asio::signal_set被破坏后我收到这个信号后,我的守护进程终止。我的猜测是这是因为boost::asio::signal_set在销毁时设置了默认处理程序,那就是终止程序,而不是以前的处理程序。

我觉得这很不合适。我问的是我错了吗?也许我错过了什么?

回答

1

Boost.Asio没有为已添加到boost::asio::signal_set然后通过signal_set::remove(),signal_set::clear()或销毁signal_set删除的信号指定结果处理程序状态。特别是,Signal Set Service requirements中的任何关联操作都没有指定后置条件。

快速一目了然的signal_set_service::add()implementation

::sigaction(signal_number, &sa, 0) 

signal_set_service::clear()implementation

struct sigaction sa; 
memset(&sa, 0, sizeof(sa)); 
sa.sa_handler = SIG_DFL; 
::sigaction(reg->signal_number_, &sa, 0) 

表明,要sigaction()呼叫没有处理以前安装的处理程序和结果的默认处理程序当通过signal_set_service删除信号时,操作被注册。 Boost.Asio的设置信号动作为默认设置后


随着信号可以传递,但是应用程序代码之前一直能够分配自己的处理程序,可以考虑使用pthread_sigmask()挡住io_service内的所有信号。一旦信号从signal_set中删除,通过sigaction()分配所需的处理程序,然后解除信号的阻塞。

下面是一个完整的例子证明这种方法:

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

void signal_handler(int signal_number) 
{ 
    std::cout << "signal_handler(): " << signal_number << std::endl; 
} 

int main() 
{ 
    // Force scope to control io_service lifetime. 
    { 
    boost::asio::io_service io_service; 

    // Boost.Asio will register an internal handler for SIGQUIT. 
    boost::asio::signal_set signal_set(io_service, SIGQUIT); 
    signal_set.async_wait(
     [](const boost::system::error_code& error, 
     int signal_number) 
     { 
     std::cout << "siganl_set.async_wait handler: " 
        << signal_number << std::endl; 

     // Block SIGQUIT. 
     sigset_t signal_mask; 
     sigemptyset(&signal_mask); 
     sigaddset(&signal_mask, SIGQUIT); 
     assert(pthread_sigmask(SIG_BLOCK, &signal_mask, NULL) == 0); 
     }); 

    // Send SIGQUIT to this process. 
    raise(SIGQUIT); 
    // By the time raise() returns, Boost.Asio has handled SIGQUIT with its 
    // own internal handler, queuing it internally. At this point, Boost.Asio 
    // is ready to dispatch this notification to a user signal handler 
    // (i.e. those provided to signal_set.async_wait()) within the 
    // io_service event loop. 

    // Prior to calling the io_service, SIGQUIT is not blocked. 
    io_service.run(); 
    // The user provided handler was invoked and has blocked SIGQUIT. 
    } 

    // Send SIGQUIT to this process. 
    raise(SIGQUIT); 
    // Even though Boost.Asio has set the default handler for SIGQUIT, the 
    // signal is blocked, so the signal has been placed into a pending state. 

    // Register a custom handler for SIGQUIT. 
    struct sigaction sa; 
    sigemptyset(&sa.sa_mask); 
    sa.sa_handler = &signal_handler; 
    assert(sigaction(SIGQUIT, &sa, 0) == 0); 

    // Unblock SIGQUIT. 
    sigset_t signal_mask; 
    sigemptyset(&signal_mask); 
    sigaddset(&signal_mask, SIGQUIT); 
    assert(pthread_sigmask(SIG_UNBLOCK, &signal_mask, NULL) == 0); 
    // Upon unblocking, the pending SIGQUIT signal is delivered and handled 
    // by the handler registered via sigaction. 

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

,其输出:

$ ./a.out 
siganl_set.async_wait handler: 3 
signal_handler(): 3 
Fin 
+0

我认为这是一个奇怪的行为不恢复旧的sigaction对象。非常非常奇怪。谢谢你的帮助!带信号阻塞可能是唯一可靠的解决方法。 – GreenScape 2014-09-01 06:38:55

相关问题