SIGINT信号,用于捕获CTRL+C终止程序。当进程收到该信号时,系统将调用该函数,并允许我们执行自定义逻辑。
但在Drogon开发使用过程中,使用signal注册了SIGINT信号,我在终端输入CTRL+C终止程序,系统并没有执行func()函数就直接退出了,百思不得其解。
static int func(int)
{
printf("Hello\n");
return 0;
}
int main(int argc, char *argv[])
{
signal(SIGINT, func); //检测SIGINT信号
drogon::app().run(); //Drogon事件循环启动
return 0;
}
经过一番追寻后,发现Drogon内部会对SIGINT信号进行处理的,而SIGINT信号只会被执行一次。当我在终端输入CTRL+C终止程序时,Drogon内部会先对信号进行处理:
1、停止接受新的连接请求,并将正在处理的请求完成(包括返回响应)。
2、关闭所有打开的数据库连接和 Redis 连接。
3、清理 epoll 相关的资源,关闭监听套接字以及所有客户端套接字。
4、退出事件循环,释放相关的资源。
处理完内部数据后,程序也就随之退出了,自定义的逻辑也就不会被调用了。
解决办法:将 signal() 函数和 signalHandler() **(Drogon内部信号处理)**函数关联起来,并在事件循环的下一个时间点执行注册操作。
代码修改成如下:
static void signalHandler(int signum)
{
// 处理 SIGINT 信号
LOG_INFO << "接收到信号" << signum;
//调用 app().quit()以退出Drogin应用程序
app().quit();
}
int main(int argc, char *argv[])
{
drogon::app().getLoop()->runAfter(0.0, [] { signal(SIGINT, signalHandler); });
drogon::app().run();
return 0;
}
以上代码中 delay 参数为 0,这意味着回调函数将被立即执行,而未来的事件在此之后将被执行。在此回调函数内部,我们使用 signal() 函数将 SIGINT 信号与 signalHandler() 函数关联起来。
这种技巧可以确保信号处理程序始终在事件循环开始后立即注册,因此不必担心信号处理程序是否已经注册完成。另外,由于信号处理程序不能在主线程中运行,因此使用 runAfter() 注册信号处理程序是一种很好的方式。