本文共 2359 字,大约阅读时间需要 7 分钟。
一、信号的概述
信号是UNIX 中所使用的进程通信的一种最古老的方法。。它是在软件层次上对中断机制的一种模拟,是一种异步通信方式。信号可以直接进行用户空间进程和内核进程之间的交互,内核进程也可以利用它来通知用户空间进程发生了哪些系统事件。它可以在任何时候发给某一进程,而无需知道该进程的状态。如果该进程当前并未处于执行态,则该信号就由内核保存起来,直到该进程恢复执行再传递给它为止;如果一个信号被进程设置为阻塞,则该信号的传递被延迟,直到其阻塞被取消时才被传递给进程。
一个完整的信号生命周期可以分为3 个重要阶段,这3 个阶段由4 个重要事件来刻画的:信号产生、信号在进程中注册、信号在进程中注销、执行信号处理函数,如下图所示:
用户进程对信号的响应有三种方式:
二、信号处理
信号处理的主要方法有两种,一种是使用简单的signal()函数,另一种是使用信号集函数组。下面分别介绍这两种处理方式。
1、使用signal()函数
使用signal()函数处理时,只需要指出要处理的信号和处理函数即可。它主要是用于前32 种非实时信号的处理,不支持信号传递信息,但是由于使用简单、易于理解,因此也受到很多程序员的欢迎。Linux 还支持一个更健壮、更新的信号处理函数sigaction(),推荐使用该函数。
函数格式:
void (*signal(int signum, void (*handler)(int)))(int)signum : 指定信号代码
handler:信号处理函数,可以是SIG_IGN、SIG_DFL、用户自定义
2、使用sigaction()函数
函数格式:
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)signum :信号代码,可以为除SIGKILL 及SIGSTOP 外的任何一个特定有效的信号
act:指向结构sigaction 的一个实例的指针,指定对特定信号的处理
oldact:保存原来对相应信号的处理
返回值:0成功,其他返回错误代码
三、测试
分别对上述两种方式实现的信号处理进行测试。他们实现的功能都是一样的,编写一个信号处理函数用来捕捉用户输入的SIGINT信号(Ctrl + C)。
1、使用signal()函数
完整测试代码如下:
#include编译并运行,结果如下:#include #include /* 自定义的信号处理函数 */void my_signal_func(int signum){ if(signum == SIGINT) { printf("Captured the signal is SIGINT!\n"); } else { printf("Cptured error!\n"); }}/* * 功能 : 捕捉SIGINT信号 */int main(void){ printf("Capture SIGINT signal!\n"); /* 捕捉相应的信号 */ signal(SIGINT, my_signal_func); /* wait a signal */ pause(); return 0;}
2、使用sigaction()函数
完整的代码如下所示:
#include编译并运行结果如下所示:#include #include #if 0struct sigaction { void (*sa_handler)(int); void (*sa_sigaction)(int, siginfo_t *, void *); sigset_t sa_mask; int sa_flags; void (*sa_restorer)(void);};#endif/* 信号处理函数 */static void my_signal_func(int signum){ if(signum == SIGINT) { printf("Captured the signal SIGINT!\n"); } else { printf("Captured error!\n"); }}/* * 功能 : 捕捉信号SIGINT */int main(void){ int ret; struct sigaction my_sigaction; printf("Capture the siganl SIGINT!\n"); /* 设置my_sigaction结构体 */ my_sigaction.sa_handler = my_signal_func; sigemptyset(&my_sigaction.sa_mask); my_sigaction.sa_flags = 0; /* 将相应的信号与信号处理函数绑定起来 */ ret = sigaction(SIGINT, &my_sigaction, 0); pause(); // wait for signal return 0;}