当前位置: 首页 > 工具软件 > Drogon > 使用案例 >

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

钱承允
2023-12-01

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() 注册信号处理程序是一种很好的方式。

 类似资料: