2014-08-27 78 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

相關問題