参考课程:(17条消息) Linux编程基础 3.3:进程同步_HenrySmale的博客-CSDN博客
本节课学习了与进程同步相关的两个函数,wait和waitpid,下面则是案例解析:
1.wait();
功能:挂起进程,进程进入阻塞状态,直到子进程变为僵尸态,如果捕获到子进程的退出信息就会转为运行态,然后回收子进程资源并返回;若没有变为僵尸态的子进程,wait函数就会让进程一直阻塞。若当前进程有多个子进程,只要捕获到一个变为僵尸态的子进程,wait函数就会恢复执行态。
参数说明:参数status是一个int *类型的指针,用来保存子进程退出时的状态信息。通常情况下该参数设为NULL,表示不关心进程时如何终止的。
返回值说明:
成功:返回子进程的进程id;
失败:返回-1,errno被设置为ECHILD。
代码案例
#include <stdio.h>
#include <sys/wait.h>
#include <stdlib.h>
int main(){
int tempStatus;
pid_t tempPid, tempW;
tempPid = fork();
if(tempPid == -1){
perror("fork error");
exit(1);
} else if(tempPid == 0){//子
sleep(3);
printf("Child process: pid=%d\n",getpid());
exit(5);
} else{//父
tempW = wait(&tempStatus);
if(WIFEXITED(tempStatus)){
printf("Child process pid=%d exit normally.\n", tempW );
printf("Return Code:%d\n",WEXITSTATUS(tempStatus));
} else {
printf("Child process pid=%d exit abnormally.\n", tempW);
}//of if
}//of if
return 0;
}//of main
运行结果
2.waitpid()
功能:
wait函数的缺点:当前进程有很多个子进程,wait函数无法保证所有子进程在父进程之前执行。
waitpid函数:可以应对 wait函数面临的缺点。可以等待指定的子进程,也可以在父进程不阻塞的情况下获取子进程的状态。
参数说明:
pid:一般是进程的pid,也有可能是其他取值。进一步说明如下:
– pid > 0:等待子进程(编号为pid)退出,若退出,函数返回;若未结束,则一直等待;
– pid = 0:等待同一进程组的所有子进程退出,若某子进程加入了其他进程组,则waitpid不再关心它的状态;
– pid = -1:waitpid函数退化为wait函数,阻塞等待并回收一个子进程;
– pid < -1:等待指定进程组中的任何子进程,进程组的id等于pid的绝对值。
options: 提供控制选项,可以是一个常量,也可以是|连接的两个常量,选项如下:
– WNOHANG:如果子进程没有终止,waitpid不会阻塞父进程,会立即返回;
– WUNTRACED:如果子进程暂停执行,waitpid立即返回;
– 0:不使用选项。
返回值说明:
成功:返回捕捉到的子进程id;
0:options = WNOHANG, waitpid发现没有已退出的子进程可回收;
-1:出错,errno被设置。
代码实现
运行结果:
3 特殊进程的危害
僵尸进程不能再次被运行,会占用一定的内存空间,并占据进程编号,当僵尸进程较多时,将会消耗系统内存,新进程可能因内存不足或无法获取pid而无法创建;
父进程通过wait()和waitpid()函数可以有效防止僵尸进程的产生,对于已存在的僵尸进程,则可通过杀死其父进程的方法解决;
当僵尸进程的父进程被终止后,僵尸进程将作为孤儿进程被init进程接收,init进程会不断调用wait()函数获取子进程状态,对已处于僵尸态的进程进行处理;
孤儿进程永远不会成为僵尸进程。
心得体会:
通过此次学习,学会了exec函数组的用法,wait与waitpid的区别与相同及其使用;并且了解了进程的异常:孤儿进程与僵尸进程。