前一篇有关信号的blog Linux中信号处理(一)中已经大概的分析了信号基本处理方法,已经signal的解析和绑定处理函数;这一篇blog来复习下信号中常用到的几个函数;
kill函数将信号发射给指定进程或者进程组,raise函数则把信号发送给自己;raise函数比较好理解,raise(int signo);kill(pid_t pid, int signo)函数就有点复杂了。其实这个函数很类似前面进程中涉及到的 waitpid()函数 Linux中进程控制函数:wait()和waitpid() ;下面着重来看下kill函数;
int kill(pid_t pid, int signo);
a、pid > 0 , 信号发送给pid进程;
b、pid == 0, 把信号发送给本进程(自己)所在的进程组中所有进程,不包括系统进程;
c、pid < 0 , 把信号发送给组id 为 -pid 的进程组中所有进程;
d、pid == -1,把信号发送给所有进程,除系统进程外(9和19号进程有些信号不接受)
前面复习了进程,所以这里特意挑出SIGCHLD信号来把信号和进程链接起来复习;当子进程退出时会发出一个SIGCHLD信号,这时候父进程可以调用wait函数来回收子进程的资源,避免子进程变成僵死进程;
下面的代码是打印下wait函数得到的退出码;
#include"common.h"
void print_status(int exitCode)
{
if (WIFEXITED(exitCode))
printf("normal termination, exitCode:%d\n", WEXITSTATUS(exitCode));
else if (WIFSIGNALED(exitCode))
printf("abnormal termination, signal number:%d\n", WEXITSTATUS(exitCode));
else if (WIFSTOPPED(exitCode))
printf("child stopped, signal number = %d\n", WSTOPSIG(exitCode));
}
下面的代码是核心
#include"common.h"
void waitChild(int signo)// 把SIGCHLD信号和该函数绑定,当父进程接受到SIGCHLD信号后调用该函数,主要是回收子进程资源
{
if (signo == SIGCHLD){
wait(&status);
}
print_status(status);// 调用上面代码,打印退出码
}
void testInt(int signo)// 和ctrl + c, SIGINT信号绑定的函数
{
printf("ctrl+c pid:%d\n", getpid());
}
void testTstp(int signo)// 和ctrl + c,SIGTSTP信号绑定的函数
{
printf("ctrl+z pid:%d\n", getpid());
}
int main(void)
{
pid_t pid;
if (0 > (pid = fork())){// 创建子进程
fprintf(stderr, "fork error!\n");
exit(1);
}else if(0 == pid){// 子进程操作区域
sleep(2);// 睡眠2秒,让父进程为SIGCHLD信号绑定好函数
printf("I am is child! pid is %d\n", getpid());
if (SIG_ERR == signal(SIGTSTP, testTstp)){ // 子进程中也让SIGTSTP信号绑定testTstp函数,主要是测试kill发信号给进程组
fprintf(stderr, "signal sigtstp error!\n");
exit(-1);
}
printf("send sigint to process group!\n");// 利用kill函数 发信号给父进程(打印语句中不应该有group)
if (-1 == kill(getppid(), SIGINT))fprintf(stderr, "kill sigint error!\n");
printf("send sigtstp to process group!\n");// 利用kill函数发送信号给自己所在的进程组
//if (-1 == kill(0, SIGTSTP))fprintf(stderr, "kill sigint error!\n");
if (-1 == kill(-(getgid()), SIGTSTP))fprintf(stderr, "kill sigint error!\n");
exit(123);// 退出,退出码为 123
}else{// 父进程操作区域
printf("I am is parent! pid is %d\n", getpid());
if (SIG_ERR == signal(SIGCHLD, waitChild)){ // 让SIGCHLD信号绑定waitChild函数
fprintf(stderr, "signal error!\n");
exit(-1);
}
if (SIG_ERR == signal(SIGINT, testInt)){ // 让SIGINT 信号绑定testInt
fprintf(stderr, "signal sigint error!\n");
exit(-1);
}
if (SIG_ERR == signal(SIGTSTP, testTstp)){ // 让SIGTSTP 信号绑定testTstp
fprintf(stderr, "signal sigtstp error!\n");
exit(-1);
}
while(1) // 死循环,等待信号
pause();
}
return 0;
}
运行结果:
从上面结果可以看出:
1、子进程把SIGINT信号发送给父进程,父进程调用了绑定的testInt()函数,打印了 pid为1364;
2、子进程把SIGTSTP信号发送给子进程所在的进程组(新fork的子进程默认和父进程在同一个进程组),可以看出父进程和子进程都调用了testTstp()函数,打印的pid分别为:1364和1365;
3、子进程退出时,发送了一个SIGCHLD信号给父进程(这是系统默认会发送的),父进程调用了绑定的waitChild()函数打印了退出码为:123;