一、信号的概述
信号是UNIX 中所使用的进程通信的一种最古老的方法。。它是在软件层次上对中断机制的一种模拟,是一种异步通信方式。信号可以直接进行用户空间进程和内核进程之间的交互,内核进程也可以利用它来通知用户空间进程发生了哪些系统事件。它可以在任何时候发给某一进程,而无需知道该进程的状态。如果该进程当前并未处于执行态,则该信号就由内核保存起来,直到该进程恢复执行再传递给它为止;如果一个信号被进程设置为阻塞,则该信号的传递被延迟,直到其阻塞被取消时才被传递给进程。
一个完整的信号生命周期可以分为3 个重要阶段,这3 个阶段由4 个重要事件来刻画的:信号产生、信号在进程中注册、信号在进程中注销、执行信号处理函数,如下图所示:
用户进程对信号的响应有三种方式:
- 忽略信号,即对信号不做任何处理,但是有两个信号不能忽略,即SIGKILL 及SIGSTOP。
- 捕捉信号,定义信号处理函数,当信号发生时,执行相应的自定义处理函数。
- 执行缺省操作,Linux 对每种信号都规定了默认操作。
二、信号处理
信号处理的主要方法有两种,一种是使用简单的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 <stdio.h>
#include <signal.h>
#include <unistd.h>
/* 自定义的信号处理函数 */
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 <stdio.h>
#include <signal.h>
#include <unistd.h>
#if 0
struct 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;
}
编译并运行结果如下所示: