在Linux中,信号捕捉是通过使用信号处理函数来实现的。信号是操作系统用于通知进程发生某些事件的机制,例如终止进程、外部中断、非法操作等。常用的信号捕捉机制是通过signal()
函数或sigaction()
函数来注册信号处理程序。
1. 使用signal()
函数
signal()
函数用于设置信号的处理函数,它的原型如下:
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
signum
:信号编号,表示要捕捉的信号。handler
:信号处理函数的指针,如果设置为SIG_IGN
,表示忽略该信号;如果设置为SIG_DFL
,表示使用默认的处理方法。
示例代码:捕捉SIGINT
(Ctrl+C)
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void sigint_handler(int sig) {
printf("Caught signal %d (SIGINT)\n", sig);
}
int main() {
// 注册信号处理程序
signal(SIGINT, sigint_handler);
printf("Waiting for SIGINT signal...\n");
// 进入一个无限循环,等待信号
while (1) {
sleep(1);
}
return 0;
}
当按下Ctrl+C
时,程序会捕获到SIGINT
信号并调用sigint_handler()
函数。
2. 使用sigaction()
函数
相比signal()
函数,sigaction()
提供了更多的控制选项,建议使用sigaction()
进行信号捕捉。
sigaction()
函数原型如下:
#include <signal.h>
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
signum
:信号编号。act
:一个指向sigaction
结构体的指针,指定信号的处理方式。oldact
:如果不为NULL
,则该参数保存原来的信号处理方式。
sigaction
结构体定义如下:
struct sigaction {
void (*sa_handler)(int); // 信号处理函数
sigset_t sa_mask; // 屏蔽信号集,在处理信号时阻塞的信号
int sa_flags; // 信号的处理标志
void (*sa_sigaction)(int, siginfo_t *, void *); // 用于捕获更多信息的信号处理函数
};
示例代码:使用sigaction
捕捉SIGTERM
(终止信号)
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void sigterm_handler(int sig) {
printf("Caught signal %d (SIGTERM)\n", sig);
}
int main() {
struct sigaction sa;
sa.sa_handler = sigterm_handler; // 设置处理函数
sigemptyset(&sa.sa_mask); // 不阻塞其他信号
sa.sa_flags = 0;
// 注册信号处理程序
sigaction(SIGTERM, &sa, NULL);
printf("Waiting for SIGTERM signal...\n");
// 进入一个无限循环,等待信号
while (1) {
sleep(1);
}
return 0;
}
在这个例子中,程序会捕获到SIGTERM
信号并调用sigterm_handler()
函数。
3. 信号常见的类型
一些常见的信号包括:
SIGINT
:从键盘发送的中断信号(通常是Ctrl+C
)。SIGTERM
:终止信号,用于优雅地终止进程。SIGKILL
:杀死进程信号,不能被捕捉或忽略。SIGSEGV
:段错误,表示非法访问内存。SIGALRM
:定时器到期信号。SIGUSR1
、SIGUSR2
:用户自定义信号。
你可以使用man 7 signal
查看更多信号类型的详细信息。
总结
signal()
:简单的信号捕捉方法,但功能较少。sigaction()
:更强大、灵活的信号捕捉方法,适合更复杂的应用场景。
对于生产环境中的信号捕捉,推荐使用sigaction()
。