一、函数介绍
sig_t signal(int signum, sig_t handler);
signum
:
此参数指定需要进行设置的信号,可使用信号名(宏)或信号的数字编号,建议使用信号名。
handler
:
sig_t
类型的函数指针,指向信号对应的信号处理函数,当进程接收到信号后会自动执行该处理函数(相当于裸机的中断,中断发生进入中断函数);参数 handler
既可以设置为用户自定义的函数(捕获信号时需要执行的处理函数),也可以设置为 SIG_IGN
或
SIG_DFL
,
SIG_IGN
表示此进程需要忽略该信号,
SIG_DFL
则表示设置为系统默认操作
。
Tips:SIG_IGN、SIG_DFL 分别取值如下:
- #define SIG_ERR ((sig_t) -1) /* Error return. */
- #define SIG_DFL ((sig_t) 0) /* Default action. */
- #define SIG_IGN ((sig_t) 1) /* Ignore signal. */
返回值:
此函数的返回值也是一个
sig_t
类型的函数指针,成功情况下的返回值则是指向在此之前的信号处理函数;如果出错则返回 SIG_ERR
,并会设置
errno
。
由此可知,
signal()
函数可以根据第二个参数
handler
的不同设置情况,可对信号进行不同的处理。
二、测试
代码:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
static void sig_handler(int sig)
{
printf("Received signal: %d\n", sig);
}
int main(int argc,char *argv[])
{
sig_t ret = NULL;
ret = signal(SIGINT,(sig_t)sig_handler);
if(SIG_ERR == ret)
{
perror("signal error");
exit(-1);
}
while(1)
{
}
exit(0);
}
在上述示例代码中,我们通过
signal()
函数将
SIGINT
(
2
)信号绑定到了一个用户自定的处理函数上sig_handler(int sig),当进程收到
SIGINT
信号后会执行该函数然后运行
printf
打印语句。当运行程序之后, 程序会卡在 for
死循环处,此时在终端按下中断符
CTRL + C
,系统便会给前台进程组中的每一个进程发送SIGINT 信号,我们测试程序便会收到该信号。
运行测试:
当运行程序之后,程序会占用终端称为一个前台进程,此时按下中断符便会打印出信息(
^C
表示按下了中断符)。平时大家使用 CTRL + C
可以终止一个进程,而这里却不能通过这种方式来终止这个测试程序,原因在于测试程序中捕获了该信号,而对应的处理方式仅仅只是打印一条语句、而并不终止进程。那此时该怎么关闭这个测试程序呢?前面给大家介绍了“一击必杀”信号 SIGKILL
(编号为
9
),可向该进程发送 SIGKILL
暴力终止该进程,当然一般不推荐大家这样使用,如果实在没办法才采取这种措施。重新打开一个终端,使用 ps
命令找到该进程的
pid
号,再使用
kill
命令,如下所示:
此时测试程序就会强制终止:
我们再执行一次测试程序,这里将测试程序放在后台运行,然后再按下中断符:
按下中断符发现进程并没有收到 SIGINT 信号,原因很简单,因为进程并不是前台进程、而是一个后台 进程,按下中断符时系统并不会给后台进程发送 SIGINT 信号。可以使用 kill 命令手动发送信号给我们的进程: