在创建进程后,为了避免僵尸进程,资源的浪费和进程数量的空闲占据,则需要对进程资源进行回收,这里主要看看wait和waitpid两个进程的功能与区别!!
一、pid_t wait(int *status)
作用(1):清理结束的子进程资源或者得到进程执行后的返回信息;
进程一旦调用了wait,就立即阻塞自己,由wait自动分析是否当前进程的某个子进程已经退出(主要是回收资源),如果让它找到了这样一个已经变成僵尸的子进程,wait就会收集这个子进程的信息,并把它彻底销毁后返回;如果没有找到这样一个子进程,wait就会一直阻塞在这里,直到有一个出现为止。
参数status:用来保存被收集进程退出时的一些状态,因为我们需要确定我们的进程是否执行成功。它是一个指向int类型的指针。但如果我们对这个子进程是如何死掉的毫不在意,只想把这个僵尸进程消灭掉,(事实上绝大多数情况下,我们都会这样想),我们就可以设定这个参数为NULL,就象下面这样:pid = wait(NULL);
如果不是NULL,wait会把子进程退出时的一些状态存入其中,这是一个整数值(int),指出子进程退出时的状态。
最常用的两个:
WIFEXITED(status): 若为正常终止, 则为真. 此时可执行 WEXITSTATUS(status): 取子进程传送给exit或_exit参数的低8位.;当WIFEXITED返回非零值时,我们可以用这个宏来提取子进程的返回值,如果子进程调用exit(5)退出,WEXITSTATUS(status) 就会返回5;如果子进程调用exit(7),WEXITSTATUS(status)就会返回7。请注意,如果进程不是正常退出的,也就是说, WIFEXITED返回0,这个值就毫无意义。WIFSTOPPED(status): 若为当前暂停子进程, 则为真. 此时可执行 WSTOPSIG(status): 取使子进程暂停的信号编号;
返回值:
成功:wait会返回被收集的子进程的进程ID;
失败:如果调用进程没有子进程,调用就会失败,此时wait返回-1。同时errno被置为ECHILD。
#include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> main() { pid_t pc,pr; pc=fork(); if(pc<0) //判断进程是否创建成功; printf("error ocurred!/n"); else if(pc==0)//如果是子进程 { printf("This is child process with pid of %d\n",getpid()); sleep(5); //让子进程等待5S; } else { //如果是父进程 pr=wait(NULL); //父进程将在这里等待5S,等待子进程的结束; printf("I catched a child process with pid of %d\n",pr); } exit(0);//正常退出; }
运行结果:
可以明显感觉到打印第二句的时候,程序等了5S,只要调用wait(),父进程就会等子进程结束后才能结束,才能捕获到子进程的状态,才能正常退出。事实上,不管我们设置多长时间,父进程都会一直等待下去。
程序实例2:
#include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include <stdio.h> main() { int status; pid_t pc,pr; pc=fork(); if(pc<0) //创建进程出错; printf("error ocurred!\n"); else if(pc==0) { //子进程 printf("This is child process with pid of %d.\n",getpid()); exit(10); //子进程成功调用后返回10,利用这个返回值看子进程是否运行顺利; } else { //父进程 pr=wait(&status); if(WIFEXITED(status)){ //如果WIFEXITED返回非零值,代表子进程执行成功; printf("the child process %d exit normally.\n",pr); printf("the return code is %d.\n",WEXITSTATUS(status)); //再次判断是否执行了我们想要执行的代码和位置; }else // 如果WIFEXITED返回零 ,则说明子进程没有执行成功; printf("the child process %d exit abnormally.\n",pr); } }
运行结果:
通过这个程序我们可以用子进程的返回值来判断子进程是否顺利执行并返回;
程序实例3:
#include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include <stdio.h> main() { pid_t pc, pr; pc=fork(); if(pc<0) // 如果fork出错 printf("Error occured on forking.\n"); else if(pc==0){ //子进程 sleep(5); // 睡眠5秒 exit(0); } // 父进程 do{ pr=waitpid(pc, NULL, WNOHANG); // 使用了WNOHANG参数,waitpid不会在这里等待,是非阻塞的wait(); if(pr==0) { // 如果没有收集到子进程,收集到会返回PID printf("No child exited\n"); sleep(1); } }while(pr==0);// 没有收集到子进程,就回去继续尝试; if(pr==pc)//找到一个子进程并回收; printf("successfully get child %d\n", pr); else printf("some error occured\n"); }运行结果:
从结果可以看出,如果加入了WNOHANG参数后,父进程就会等待子进程的结束,但是不会一直等待下去,而是间断的去轮询,这样提高了程序的运行效率。不是死等!!
当fork调用成功后,父子进程各做各的事情,但当父进程的工作告一段落,需要用到子进程的结果时,它就停下来调用wait,一直等到子进程运行结束,然后利用子进程的结果继续执行,这样就圆满地解决了我们提出的进程同步问题。
程序实例:
#include <sys/types.h> #include <sys/wait.h> #include <stdio.h> main() { pid_t pc, pr; int status,a,b,c,sum; a=10; b=2; pc=fork(); if(pc<0) printf("Error occured on forking.\n"); else if(pc==0) { //子进程的工作,算C的值; printf("this is child process,ID:%d,PID:%d.",getpid(),getppid()); c=a+b; exit(c); } else { // 父进程的工作 pr=wait(&status); //利用子进程的结果 C; if(WIFEXITED(status)) //如果WIFEXITED返回非零值,代表子进程执行成功; { printf("this is father process,ID:%d.\n",getpid()); sum=WEXITSTATUS(status);//得到子进程的结果; printf("%d\n",sum);//输出子进程的结果; } else { printf("the child process %d exit abnormally.\n",pr); } } }运行结果: 这个程序就可以说明,父进程的工作依赖于子进程的执行结果,所以必须等待子进程的结束;
wait&waitpid 区别 :
waitpid提供了wait函数不能实现的3个功能:
(1)、waitpid等待特定的子进程, 而wait则返回任一终止状态的子进程;ret=waitpid(-1,NULL,WNOHANG);//无阻塞的wait(); pr=waitpid(pc, NULL, 0);与pr=wait(NULL)就完全一模一样了;WUNTRACED:它涉及到一些跟踪调试信息;
static inline pid_t wait(int * wait_stat) { return waitpid(-1,wait_stat,0); }返回值和错误
http://blog.csdn.net/kevinhg/article/details/7001719
http://blog.sina.com.cn/s/blog_590be5290100nc51.html
http://blog.chinaunix.net/uid-25365622-id-3045460.html
感谢博主的分享!