exec函数族?
fork:子进程复制父进程的堆栈段和数据段,子进程一旦开始运行,它继承了父进程的一切数据,但实际上数据却已经分开,相互之间不再影响
exec:一个进程调用exec类函数,它本身就"死亡"了,系统把代码段替换成新的程序代码,废弃原有数据段和堆栈段,并为新程序分配新数据段与堆栈段
wait()函数:
功能:调用wait()函数的进程会被挂起, 进入阻塞状态,直到wait()捕捉到僵尸子进程并回收该子进程的资源,若没有僵尸子进程,wait()函数则会让进程一直处于阻塞状态。
若当前由多个进程, 只需要捕捉到一个僵尸子进程, wait()函数就会返回并是进程恢复执行。
若子进程是其父进程的先决进程,调用wait()进程使进程同步。
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
int main()
{
pid_t tempPid, tempW;
tempPid = fork();
if (tempPid == -1){ //error
perror("fork error.\n");
exit(1);
}
else if(tempPid == 0){ //child process
sleep(3);
printf("this is child process, pid = %d, ppid = %d\n", getpid(), getppid());
}
else{ //parent process
tempW = wait(NULL); // wait() returns child process's pid
printf("Create a child process, pid = %d, ppid = %d\n", tempW, getppid());
}
printf("finish!!\n");
return 0;
}
wait()进程具有一定的局限性:若当前由多个子进程,那么该函数无法确保作为先决条件的子进程在父进程之前执行。需要使用waitpid() 来解决这一问题。
waitpid()
功能:waitpid()可以等待指定的子进程,也可以在父进程不阻塞的情况下获取子进程的状态。
waitpid()等待指定子进程
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
int main()
{ pid_t tempPid, tempW, tempP;
tempPid = fork();
if(tempPid == -1){
perror("fork1 error.\n");
exit(1);
}
else if(tempPid == 0){
sleep(5); // 该进程睡眠5秒
printf("Create the first child process, pid = %d, ppid = %d\n", getpid(), getppid());
}
else{
tempP = tempPid; // tempP 存放 第一个子进程的pid
int i;
for (i = 0; i<3; i++){ // 创建三个新的子进程
if((tempPid = fork()) == 0){
break;
}
}
if(tempPid == -1){
perror("fork error\n");
exit(2);
}
else if(tempPid == 0){
printf("child process, pid = %d\n", getpid());
exit(0);
}
else{
tempW = waitpid(tempP, NULL, 0); // pid参数赋值为 第一个子进程的pid, 指定收集该进程
if(tempW == tempP){ // 若收集成功,则waitpid()返回值为被回收进程的pid
printf("Catch a child process:pid = %d\n", tempW);
}
else{
printf("wait error.\n");
}
}
}
return 0;
}
两种特殊进程
孤儿进程:
当父进程在子进程退出之前退出,子进程就变成孤儿进程。此时子进程会被init进程收养,之后由init进程代替原来的父进程完成状态收集工作。
僵尸进程:
僵尸进程几乎放弃了退出前占用的所有内存资源,只在进程列表中保留一个位置,记载进程的退出状态码等信息共父进程收集。若父进程未回收,子进程将一直处于僵尸状态。
特殊进程的危害
僵尸进程不能再次被运行,会占用一定的内存空间,并占据进程编号,当僵尸进程较多时,将会消耗系统内存,新进程可能因内存不足或无法获取pid而无法创建;
父进程通过wait()和waitpid()函数可以有效防止僵尸进程的产生,对于已存在的僵尸进程,则可通过杀死其父进程的方法解决;
当僵尸进程的父进程被终止后,僵尸进程将作为孤儿进程被init进程接收,init进程会不断调用wait()函数获取子进程状态,对已处于僵尸态的进程进行处理;
孤儿进程永远不会成为僵尸进程。