过用wait和waitpid函数清理僵尸进程,父进程可以阻塞等待子进程结束,也可以非
阻塞地查询是否有子进程结束等待清理(也就是轮询的方式)。采用第一种方式,父进程阻塞
了就不能处理自己的工作了;采用第二种方式,父进程在处理自己的工作的同时还要记得时不
时地轮询一下,程序实现复杂。
其实,子进程在终止时会给父进程发SIGCHLD信号,该信号的默认处理动作是忽略,父进程可以
自定义SIGCHLD信号的处理函数,这样父进程只需专心处理自己的工作,不必关心子进程了,子
进程终止时会通知父进程,父进程在信号处理函数中调用wait清理子进程即可。
**请编写一个程序完成以下功能:父进程fork出子进程,子进程调用exit(2)终止,父进程自定
义SIGCHLD信号的处理函数,在其中调用wait获得子进程的退出状态并打印。**
1 #include <unistd.h>
2 #include <stdlib.h>
3 #include <signal.h>
4 #include <stdio.h>
5 #include <sys/types.h>
6 #include <sys/wait.h>
7
8 pid_t pid;//全局变量,sigchld和main函数都要访问
9
10 void sig_chld(int signo){//信号处理函数
11 int stat_val;//该值由获取到的pid值来决定内容
12 waitpid(pid,&stat_val,0);//0代表不需要第三个参数作用
13 if(WIFEXITED(stat_val))
14 printf("child exited with code %d\n", WEXITSTATUS(stat_val));
15 //WIFEXITED(status) 若此值为非0 表明进程正常结束。
16 //若上宏为真,此时可通过WEXITSTATUS(status)获取进程退出状态(exit时参数)
17 else if(WIFSIGNALED(stat_val))
18 printf("Child terminated abnormally, signal %d\n", WTERMSIG(stat_val));
19 //WIFSIGNALED(status)为非0 表明进程异常终止。
20 //若上宏为真,此时可通过WTERMSIG(status)获取使得进程退出的信号编号
21 }
22
23 int main(void){
24 struct sigaction newact,oldact;
25 //内核头文件中,struct sigaction 结构体定义在kernel/include/asm/signal.h,此头文件又被kernel/include/linux/signal.h包
含。
26 //用户空间的头文件而言,struct sigaction定义在 /usr/include/bits/sigaction.h,此头文件又被/usr/include/signal.h包含
27 newact.sa_handler = sig_chld;//此处sa_handler是一个函数指针,接收一个函数名(sig_chld)
28 sigemptyset(&newact.sa_mask);//初始化屏蔽字
29 newact.sa_flags = 0;//初始化
30 sigaction(SIGCHLD,&newact,&oldact);//把前面的newact内容备份到oldact
31
32 pid = fork();
33 if(pid < 0){
34 perror("fork");
35 exit(1);
36 }
37 if(pid > 0)//父进程返回子进程pid,>0表示为父进程 /* parent */
38 {
39 while (1);
40 }else{//fork调用后,父子进程各返回一次,但顺序不确定,pid==0 /* child */
41 exit(2);
42 }
43 sigaction(SIGCHLD,&oldact,NULL);//再备份回来,oldact非空,根据他来修改信号处理动作
44 return 0;
45 }
46
用的vscode远程连接centos7环境,因为vim以及linux里面调试太难用了啊啊啊啊
linux环境下运行结果如下:
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。