1.signal函数
#include
void (*signal(int signo, void (*func)(int)))(int);
返回:若成功则返回先前的信号处理函数指针,出错则返回SIG_ERR;
功能:向内核登记信号处理函数;
参数:signo:要登记的信号值
func:a.信号处理函数指针;b.SIG_IGN,忽略信号;c.SIG_DFL,采用系统默认的方式处理信号,执行默认操作
2.进程对信号的三种响应
下面以SIGINT信号为例,对这三种响应方式进行说明。
(1)忽略信号,signal(SIGINT,SIG_IGN);
SIG_IGN代表忽略SIGINT信号,SIGINT信号代表由InterruptKey产生,通常是Ctrl+C或者是DELETE。发送给所有ForeGround Group的进程。
下面我们写个死循环:
#include
#include
int main(void)
{
signal(SIGINT, SIG_IGN);
for(;;);
return 0;
}
这时我们保存执行,按下Ctrl+C程序没有反应,这就对了。
如果我们想结束该程序可以按下Ctrl+\来结束
其实当我们按下Ctrl+\组合键时,是产生了SIGQUIT信号。
(2)执行默认操作,signal(SIGINT, SIG_DFL)
SIG_DFL代表执行系统默认操作,其实对于大多数信号的系统默认动作是终止改进程,与不写此处理函数的效果是一样的。
#include
#include
int main(void)
{
signal(SIGINT, SIG_DFL);
for(;;);
return 0;
}
这时就可以按下Ctrl+C来终止该进程了。把signal(SIGINT, SIG_DFL)这句去掉,效果是一样的。
(3)捕获信号,signal(SIGINT, sig_handler);
#include
#include
void sig_handler(int signo)
{
printf("catch the signal:%d", signo);
}
int main(void)
{
// 登记一下SIGINT信号
if(signal(SIGINT, sig_handler) == ERR)
printf("signal error");
for(;;);
return 0;
}
这种情况下,当按下Ctrl+C时,会执行我们定义的信号处理函数。
想要退出,可以按下Ctrl+\
3.对信号处理的几点说明
(1) SIGKILL和SIGSTOP这两个信号永远不能忽略;
(2) SIGKILL和SIGSTOP不能被捕获(即使已经登记了,也不能被捕获);
(3) 进程启动时SIGUSR1和SIGUSR2两个信号被忽略;
4.几个常见的信号
(1)SIGINT,编号为2,相当于执行Ctrl+C;
(2)SIGTSTP,编号为20,相当于Ctrl+Z,暂停一个进程;
(3)SIGCONT,编号为18,继续执行被暂停的信号,格式为:kill -SIGCONT/18 进程ID;
(4)SIGCHLD,编号为17,子进程结束产生该信号;(信号的异步处理表现在:当SIGCHLD产生时,父进程对其捕获处理,其他时间父进程该干嘛干嘛)
下面举例来说明SIGCHLD信号的用法。
#include
#include
#include
#include
#include
#include
void sig_handler(int signo)
{
printf("child process deaded, signo: %d\n", signo);
wait(0);// 当捕获到SIGCHLD信号,父进程调用wait回收,避免子进程成为僵尸进程
}
void out(int n)
{
int i;
for(i = 0; i < n; ++i)
{
printf("%d out %d\n", getpid(), i);
sleep(2);
}
}
int main(void)
{
// 登记一下SIGCHLD信号
if(signal(SIGCHLD, sig_handler) == SIG_ERR)
{
perror("signal sigchld error");
}
pid_t pid = fork();
if(pid < 0)
{
perror("fork error");
exit(1);
}
else if(pid > 0)
{
// parent process
out(100);
}
else
{
// child process
out(10);
}
return 0;
}