> 文章列表 > Drogon中signal注册的SIGINT信号没有被触发调用

Drogon中signal注册的SIGINT信号没有被触发调用

Drogon中signal注册的SIGINT信号没有被触发调用

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;
}
  • drogon::app() 获取一个指向应用程序对象的智能指针。
  • getLoop() 获取应用程序对象所使用的事件循环对象。
  • runAfter(delay, callback) 方法将指定的 callback 回调函数在延迟 delay 秒后添加到事件循环中执行。

以上代码中 delay 参数为 0,这意味着回调函数将被立即执行,而未来的事件在此之后将被执行。在此回调函数内部,我们使用 signal() 函数将 SIGINT 信号与 signalHandler() 函数关联起来。

这种技巧可以确保信号处理程序始终在事件循环开始后立即注册,因此不必担心信号处理程序是否已经注册完成。另外,由于信号处理程序不能在主线程中运行,因此使用 runAfter() 注册信号处理程序是一种很好的方式。