信号是Linux进程间通信的一种异步机制,它可以在任何时候通知进程某个事件发生了。默认情况下,大多数信号会终止进程,但我们可以通过信号捕抓来改变这一行为,让进程在收到信号时执行自定义的操作,比如清理临时文件、记录日志或优雅退出。本文将带你从零开始,全面掌握Linux下的信号捕抓技术。
信号捕抓(Signal Handling)是指进程在收到某个信号时,不执行默认动作,而是调用预先设置的用户态函数(称为信号处理函数)来处理该信号。通过捕抓信号,我们可以让进程对外部事件做出自定义响应。例如,当按下Ctrl+C时,默认发送SIGINT终止进程,但我们可以捕抓它,执行保存数据等操作后再退出。
Linux提供了两个常用的系统调用来设置信号处理函数:signal函数和sigaction函数。前者简单易用,后者功能更强大且可移植性更好。
signal()是ANSI C定义的函数,原型为:void (signal(int signum, void (handler)(int)))(int);。它接受两个参数:要捕抓的信号编号和新的处理函数指针,返回之前设置的处理函数指针。使用示例如下:
#include #include #include void sigint_handler(int sig) {printf("捕获到SIGINT信号,执行自定义操作...");}int main() {// 捕抓SIGINT信号(Ctrl+C)if (signal(SIGINT, sigint_handler) == SIG_ERR) {perror("signal error");return 1;}while(1) {printf("程序运行中...");sleep(1);}return 0;} 运行该程序后,按Ctrl+C不会终止进程,而是打印消息后继续运行(注意:有些系统在信号处理函数返回后可能会重新执行被中断的系统调用,这里sleep会被中断,但while循环继续)。
sigaction函数是POSIX标准推荐的信号处理接口,它提供了更精细的控制,比如指定信号处理函数的执行方式、屏蔽其他信号等。其原型为:
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); 其中struct sigaction结构体至少包含以下成员:
sa_handler:信号处理函数指针,与signal类似。sa_sigaction:当使用SA_SIGINFO标志时,使用该字段指定带额外参数的函数。sa_mask:在调用处理函数期间要阻塞的信号集。sa_flags:控制信号处理行为的标志位,如SA_RESTART让被中断的系统调用自动重启。示例:使用sigaction捕抓SIGINT并自动重启被中断的系统调用。
#include #include #include void handler(int sig) {printf("收到信号 %d", sig);}int main() {struct sigaction sa;sa.sa_handler = handler;sigemptyset(&sa.sa_mask);sa.sa_flags = SA_RESTART; // 让read、sleep等系统调用自动重启if (sigaction(SIGINT, &sa, NULL) == -1) {perror("sigaction");return 1;}while(1) {printf("等待信号...");sleep(3); // 会被信号中断,但由于SA_RESTART,它会自动重启}return 0;}
信号处理函数是在异步上下文中执行的,因此必须遵守一些限制:只能调用异步信号安全的函数(即可重入函数),比如write,但不能调用printf(除非你很确定它的实现是安全的)。通常建议处理函数尽量简单,例如只设置一个全局标志,然后主循环检查该标志。避免使用全局变量,如果必须使用,应声明为volatile sig_atomic_t类型以保证原子访问。
有时我们需要临时阻塞某些信号,防止它们中断关键代码段。Linux提供了信号集(sigset_t)和相关操作函数,如sigemptyset、sigaddset、sigprocmask。通过sigprocmask可以设置进程的信号屏蔽字,阻塞或解除阻塞指定信号。示例:
sigset_t newmask, oldmask;sigemptyset(&newmask);sigaddset(&newmask, SIGINT);// 阻塞SIGINTif (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0) {perror("sigprocmask");}// 执行关键代码...// 恢复旧的信号屏蔽字sigprocmask(SIG_SETMASK, &oldmask, NULL); 通过本文的学习,你应该已经掌握了Linux信号捕抓的核心概念和两种主要实现方式:signal函数和sigaction函数。同时了解了信号处理函数的编写要点以及信号屏蔽的基本用法。在实际开发中,建议优先使用sigaction以获得更好的可控性和可移植性。信号机制是Linux系统编程的重要基础,掌握它能让你的程序更加健壮和灵活。
关键词:Linux信号捕抓、signal函数、sigaction函数、信号处理函数。
本文由主机测评网于2026-02-16发表在主机测评网_免费VPS_免费云服务器_免费独立服务器,如有疑问,请联系我们。
本文链接:https://www.vpshk.cn/20260225399.html