为什么要有信号处理
程序在执行过程中可能会被系统关闭,譬如在命令行执行时用户按下CTRL+C终止执行,或者在进程管理时直接终止,为了保证程序能够正常退出,来释放所有占用的资源,做一些必要的退出前处理,都需要能够捕获到这些信号并进行处理。
C++标准的处理方法
C++提供了signal方法用来安装一个信号处理handler来替换默认的处理handler:
//Visual Studio 2015中的定义
typedef void (__CRTDECL* _crt_signal_t)(int); //处理handler定义
_crt_signal_t __cdecl signal(_In_ int _Signal, _In_opt_ _crt_signal_t _Function);
Boost.Asio
中的signal_set
Boost.Asio
中定义了signal_set
来进行系统信号的响应,其使用io_service
和要相应的信号构造,提供了如下方法:
- add:添加一个信号
- remove:移除一个信号
- clear:移除其所有信号
- async_wait:启动异步操作等待接收信号
信号的通知
信号发生后会被排队到队列,在有async_wait
的情况下会发出通知,当多个信号发生,也会一个一个地通知,如果信号被从signal_set
中移除则对应的通知会被抛弃。
使用方法
示例如下:
void handler( const boost::system::error_code& error, int signal_number)
{
if (!error)
{
// 信号发生了
}
}
...
// 构造signal set 来接收进程终止消息.
boost::asio::signal_set signals(io_service, SIGINT, SIGTERM);
// 启动异步操作等待信号发生
signals.async_wait(handler);
注意事项
相同的信号可以被注册到不同的signal_set
,当信号发生时所有signal_set
的处理handler均会被调用;多次注册只是在Boost.Asio
中能够使用;如果使用signal_set
就不要再使用其它方式注册信号处理handler了。
在Boost.Asio
中如何使用
当接收到对应信号后就需要进行清理流程了,如果启动了io_service.run
,可以在清理流程中调用io_service.stop
,这样io_service.run
会尽可能快地退出,所有的异步操作等都会被抛弃,示例如下:
class server
{
public:
server(unsigned short port)
:signals_(io_,SIGINT,SIGTERM),
acceptor_(io_,tcp::endpoint(tcp::v4(),port)),
socket_(io_)
{
}
~server() { io_.stop(); };
void listen()
{
//当接收到中断信号就停止服务执行退出流程
signals_.async_wait([this](const boost::system::error_code& ec,int signal_number){
if (!ec)
{
io_.stop();
std::cout<<"server stopping\n";
}
});
do_accept();
io_.run();
}
void do_accept()
{
acceptor_.async_accept(socket_, [this](boost::system::error_code ec) {
if (!ec)
{
......
}
else
{
std::cerr << ec.message() << std::endl;
}
do_accept();//继续发起accept流程阻止run退出
});
}
private:
boost::asio::io_service io_;
boost::asio::signal_set signals_;
tcp::acceptor acceptor_;
tcp::socket socket_;
};
网友评论