有关服务端退出方法的笔记 C风格的信号关闭boost::asio中的关闭方式
原来服务端的main函数如下
int main()
{try{boost::asio::io_context ioc;Server s(ioc, 8888);ioc.run();}catch (const std::exception&){}return 0;
}
上面弊端在于缺乏好的退出机制,目前,ioc.run() 会一直阻塞,直到 io_context 被显式地停止。然而,如果没有显式的退出信号或退出条件(如 SIGINT、SIGTERM 信号等),程序将无法优雅地退出。万一在运行时出现异常,或者程序需要在特定时机停止时,缺乏退出机制可能导致程序无法正常关闭。 如果服务器程序无法响应中断信号或其他退出信号,可能会影响系统资源的释放,造成资源泄漏(如打开的网络连接、文件句柄等)。
C风格的信号关闭
#include
#include
#include "Session.h"
#include
#include
#include
std::condition_variable cond_quit;
std::mutex mutex_quit;void sig_handle(int sig)
{if (sig == SIGINT || sig == SIGTERM){std::unique_lock
}int main()
{try{boost::asio::io_context ioc;std::thread net_work([&ioc] {Server s(ioc, 8888);ioc.run();});signal(SIGINT, sig_handle);signal(SIGTERM, sig_handle);while (!bstop){std::unique_lock
}
这里可以看到,不同于之前的主线程来进行轮询、收发数据的处理,这里采用了使用一个新线程net_work来负责原先主线程的任务,然后主线程负责监听SIGINT和SIGTERM两个信号 当程序正在运行的时候,如果想要终止程序,我们就可以通过向该进程发送信号来执行终止逻辑sig_handle。下面简单介绍一下主线程在干什么
signal(SIGINT, sig_handle);
signal(SIGTERM, sig_handle);
while (!bstop)
{std::unique_lock
}
ioc.stop();
net_work.join();
在while循环内部,定义了一个std::unique_lock
void sig_handle(int sig)
{if (sig == SIGINT || sig == SIGTERM){std::unique_lock
}
在这个函数中,会将bstop设置为true,表示整个程序应该要终止了,然后去唤醒主线程告诉它要去进行收尾的逻辑
ioc.stop();
net_work.join();
回到主线程,退出循环之后,停止掉ioc,然后去等待回收net_work线程,回收之后再退出,此时整个程序也就安全退出了
boost::asio中的关闭方式
int main()
{try{boost::asio::io_context ioc;boost::asio::signal_set signals(ioc, SIGINT, SIGTERM);signals.async_wait([&ioc](auto, auto) {ioc.stop();});Server s(ioc, 8888);ioc.run();}catch (const std::exception&){}return 0;
}
boost::asio::signal_set signals(ioc, SIGINT, SIGTERM);
这一行创建了一个 boost::asio::signal_set 对象signals。signal_set 用于注册对特定信号(如中断信号 SIGINT 或终止信号 SIGTERM)的异步处理。这里注册了 SIGINT(通常是按下 Ctrl+C 时触发)和 SIGTERM(终止进程的信号)信号。 signals 会监听这些信号,并触发相关的回调函数。
signals.async_wait([&ioc](auto, auto) { ioc.stop(); });
这行代码使用了 async_wait 来等待信号的异步触发。回调函数会在 SIGINT 或 SIGTERM 信号到达时被调用。在回调函数内部,调用了 ioc.stop(),这会停止 io_context 的事件循环。当信号到达时,ioc.stop() 会中断事件循环的运行,允许程序优雅地退出