转自  http://blog.csdn.net/todd911/article/details/15028511

1.wait函数和waitpid函数

当一个进程正常或异常终止时,内核就向其父进程发送SIGCHLD信号。因为子进程终止是个异步事件,所以这种信号也是内核向父进程发的异步通知。父进程可以选择忽略信号,或者提供一个该信号的处理函数,对于这种信号默认动作是忽略它。调用wait或waitpid的进程可能会发生什么情况:

  • 如果其所有子进程都在运行,则阻塞。
  • 如果一个子进程已经终止,正等待父进程获取其终止状态,则取得该子进程的终止状态后返回。
  • 如果它没有任何子进程,则立即出错返回。
#include <sys/wait.h>
pid_t wait(int *statloc); //如果成功返回进程ID,0,如果出错返回-1.
pid_t waitpid(pid_t pid, int *statloc, int options); //如果成功返回进程ID,0(使用WNOHANG选项),如果出错返回-1.

这两个函数的区别是:

  • 在一个子进程终止前,wait使其调用者阻塞,而waitpid有一个选项,可使调用者不阻塞。
  • waitpid并不等待在其调用之后的第一个终止子程序,它有若干个选项,可以控制它所等待的进程。
statloc是一个整型指针,如果statloc不是一个空指针,则终止进程的终止状态就存放在它所指向的单元内,如果不关心终止状态,则可将该参数指定为空指针。可以使用一下四个宏来查看进程的终止状态。
 
实践:
#include <stdio.h>
#include <sys/wait.h>
#include <stdlib.h> void pr_exit(int status){
printf("status = %d\n", status);
if(WIFEXITED(status)){
printf("normal terminaton, exit status = %d\n", WEXITSTATUS(status));
}else if(WIFSIGNALED(status)){
printf("abnormal termination, signal number = %d%s\n",WTERMSIG(status),
#ifdef WCOREDUMP
WCOREDUMP(status)?"(core file generated)" : "");
#else
"");
#endif
}else if(WIFSTOPPED(status)){
printf("child stopped, signal number = %d\n", WSTOPSIG(status));
}
} int main(void){
pid_t pid;
int status; if((pid = fork()) < ){
perror("fork");
return -;
}else if(pid == ){
exit();
}
if(wait(&status) != pid){
perror("wait");
return -;
}
pr_exit(status); if((pid = fork()) < ){
perror("fork");
return -;
}else if(pid == ){
abort();
}
if(wait(&status) != pid){
perror("wait");
return -;
}
pr_exit(status); if((pid = fork()) < ){
perror("fork");
return -;
}else if(pid == ){
status /= ;
}
if(wait(&status) != pid){
perror("wait");
return -;
}
pr_exit(status); return ;
}
运行结果:
[yan@yanPC apue]$ ./a.out
status = 1792
normal terminaton, exit status = 7
status = 134
abnormal termination, signal number = 6(core file generated)
status = 136
abnormal termination, signal number = 8(core file generated)
 
waitpid可以等待一个特定的进程结束。对于waitpid函数中的pid参数的作用解释如下:
pid == -1    等待任意子进程,与wait等效。
pid > 0  等待进程ID等于pid的子进程。
pid == 0  等待其组ID等于调用进程组ID的任意子进程。
pid < -1 等待其组ID等于pid绝对值的任一子进程。
options参数使我们能进一步控制waitpid的操作。参数可以是0(不是用options),或是下表常量或运算的结果:
实践:
#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h> int main(void){
pid_t pid;
int status; if((pid = fork()) < ){
perror("fork");
return -;
}else if(pid == ){
sleep();
_exit();
} while(waitpid(pid,&status,WNOHANG) == ){
printf("no terminated process.\n");
sleep();
}
printf("child terminated.\n");
return ;
}  
运行结果:
yan@yan-vm:~/apue$ ./a.out
no terminated process.
no terminated process.
no terminated process.
no terminated process.
no terminated process.
child terminated.
使用了WNOHANG,因为没有结束的子进程,waitpid直接返回。
 
2.waitid函数
Single Unix Specification的XSI扩展包括了另一个取得进程终止状态的函数--waitid,该函数类似于waitpid,但提供了更多的灵活性。
#include <sys/wait.h>
int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
//若成功则返回0,出错则返回-1.
id参数的作用与idtype的值相关,详细如下表:
options参数是下表各标志的按位或:
infop参数指向siginfo结构的指针,该结构包含了有关引起进程状态改变的生成信号的详细信息。
实践:
#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h> int main(void){
pid_t pid, pid2;
siginfo_t info; if((pid = fork()) < ){
perror("fork");
return -;
}else if(pid == ){
sleep();
_exit();
}
while((pid2 = waitid(P_PID,pid,&info,WNOHANG)) == -){
printf("no terminated process %d.\n",pid2);
sleep();
} return ;
}
运行结果:
no terminated process -1.
no terminated process -1.
no terminated process -1.
no terminated process -1.
no terminated process -1.
no terminated process -1.
no terminated process -1.
no terminated process -1.
.......
按照说明,waitid一直返回-1,也就是一直出错,再看下进程状态。
yan       5147  0.0  0.0   2008   280 pts/2    S    14:10   0:00 ./a.out
yan       5148  0.0  0.0      0     0 pts/2    Z    14:10   0:00 [a.out] <defunct>
子程序已经僵死了,但是父进程无法回收它,这边真的不明白是什么原因,望高人指点~~~~
 
3.wait3和wait4函数
大多数UNIX系统实现了另外的两个函数wait3和wait4.历史上,这2个函数是UNIX系统的BSD分支沿袭下来的。它们提供的功能比POSIX.1函数wait,waitpid和waitid所提供的功能要多一个,这与附加参数rusage有关,该参数要求内核返回由终止进程及其所有子进程使用的资源汇总。
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>
pid_t wait3(int *statloc, int options, struct rusage *rusage);
pid_t wait4(pid_t pid, int *statloc, int option, struct rusage *rusage);
//两个函数返回值,若成功,则返回进程ID,若出错,则返回-1.
资源统计信息包括用户CPU时间总量,系统CPU时间总量,页面出错次数,接受到信号次数等,下表列出了各个wait函数所支持的参数。
 
4.一种避免僵死进程的方法
使用2次fork,即使不对子进程进行回收也不会出现僵死进程。
#include <stdio.h>
#include <sys/wait.h>
#include <stdlib.h> int main(void){
pid_t pid;
if((pid = fork()) < ){
perror("fork");
return -;
}else if(pid == ){
if((pid = fork()) < ){
perror("fork");
return -;
}else if(pid > ){
exit();
}else{
sleep();
printf("second child,parent pid = %d\n",getppid());
exit();
}
} if(waitpid(pid,NULL,) != pid){ //回收第一次fork的子进程
perror("waitpid");
return -;
}
return ;
}
运行结果:
yan@yan-vm:~/apue$ ./a.out
yan@yan-vm:~/apue$ second child,parent pid = 1
parent id为1,即被init收养了。 

最新文章

  1. C语言系统时间读取
  2. C#根据网址生成静态页面
  3. Memcache知识点梳理
  4. 【转】敏捷开发 Scrum 总结
  5. 经过本人 6 年.net 工作经验证明 .net 工资确实比 Java 低
  6. C++面向对象编程解决三阶矩阵相加减
  7. jQuery UI的基本使用方法与技巧
  8. HDU 5145 NPY and girls(莫队算法+乘法逆元)
  9. This application failed to start because it could not find or load the Qt platform plugin &amp;quot;xcb&amp;quot;.
  10. Latex 论文elsevier,手把手如何用Latex写论文
  11. zTree分批异步加载方式下实现节点搜索功能(转载)
  12. ASP.NET实现头像剪切保存
  13. Log4j按级别输出日志到不同文件配置
  14. bzoj1034 泡泡堂
  15. 我的Git教程 之 初始化本地库
  16. Android Path Time ScrollBar(Path 时间轴)
  17. 【BZOJ2084】【洛谷P3501】[POI2010]ANT-Antisymmetry(Manache算法)
  18. Windows操作系统下 使用c++ WIN32API禁用控制台最小化和关闭按钮
  19. 【Leetcode】【Easy】Merge Sorted Array
  20. May 23rd 2017 Week 21st Tuesday

热门文章

  1. 2019杭电多校一 C. Milk (dp)
  2. sql注入测试(2)---实例测试
  3. Visual Studio 2017修改编码UTF-8
  4. Rider开发开发.NET Framework 4.5项目遇到的一些问题
  5. .net core mvc + mysql dbfirst 生成 ado.net 数据模型
  6. 表空间 oracle
  7. js基本对象
  8. c# 引用与对象举例
  9. jquery.js:9600 POST http://127.0.0.1:8000/news/1/comments/ 500 (Internal Server Error)
  10. 【转】Golang汇编命令解读