- 学习内容
- exec函数族
- 进程退出
- 特殊进程
- wait函数和waitpid函数
- 代码
- exec
- 运行结果
- 【案例 1】
- 【案例 2】
- 【案例 3】
- 【案例 4】
- 总结
学习内容
链接:
进程管理
进程同步
exec:一个进程调用exec类函数,它本身就"死亡"了,系统把代码段替换成新的程序代码,废弃原有数据段和堆栈段,并为新程序分配新数据段与堆栈段
exec函数族中包含6个函数,分别为:
#includeint execl(const char *path, const char *arg, ...); int execlp(const char *file, const char *arg, ...); int execle(const char *path, const char *arg, ..., char * const envp[]); int execv(const char *path, char * const argv[]); int execvp(const char *file, char * const argv[]); int execve(const char *path, char * const argv[], char * const envp[]);
参数说明:
(1)当参数是path,传入的为路径名;当参数是file,传入的可执行文件名;
(2)可以将exec函数族分为execl和execv两类:
execl类:函数将以列举的形式传入参数,由于参数列表的长度不定,所以要用哨兵NULL表示列举结束;
execv类:函数将以参数向量表传递参数,char * argv[]的形式传递文件执行时使用的参数,数组中最后一个参数为NULL;
(3)如果没有参数char * const envp[],则采用默认环境变量;如果有,则用传入的参数替换默认环境变量;
#include特殊进程void exit(int status);
孤儿进程:父进程负责回收子进程,如果父进程在子进程退出之前退出,子进程就会变成孤儿进程,此时init进程将代替父进程完成子进程的回收工作;
僵尸进程:调用exit函数后,该进程不会马上消失,而是留下一个称为僵尸进程的数据结构。它几乎放弃进程退出前占用的所有内存,既没有可执行代码也不能被调度,只是在进程列表中保留一个位置,记载进程的退出状态等信息供父进程回收。若父进程没有回收子进程的代码,子进程将会一直处于僵尸态。
wait函数和waitpid函数wait函数功能:挂起进程,进程进入阻塞状态,直到子进程变为僵尸态,如果捕获到子进程的退出信息就会转为运行态,然后回收子进程资源并返回;若没有变为僵尸态的子进程,wait函数就会让进程一直阻塞。若当前进程有多个子进程,只要捕获到一个变为僵尸态的子进程,wait函数就会恢复执行态。
wait函数的缺点:当前进程有很多个子进程,wait函数无法保证所有子进程在父进程之前执行。
waitpid函数:可以应对 wait函数面临的缺点。可以等待指定的子进程,也可以在父进程不阻塞的情况下获取子进程的状态。
代码 exec
#include运行结果#include #include int main(){ pid_t tempPid; tempPid=fork(); if(tempPid ==-1){ perror("fork error"); exit(1); } else if(tempPid >0){ printf("parent process:pid=%dn",getpid()); } else{ printf("child process:pid=%dn",getpid()); char *arg[]={"-a","-1","main.c",NULL}; execvp("ls",arg); perror("error execn"); printf("child process:pid=%dn",getpid()); }// of if return 0; }// of main
【案例 1】结果如下:
若子进程p 1 是其父进程p 的先决进程,基于wait函数使得进程同步。
#include#include #include int main(){ pid_t tempPid, tempW; tempPid = fork(); if(tempPid == -1){ perror("fork error"); exit(1); }else if(tempPid == 0){//child sleep(3); printf("Child process, pid = %d, ppid = %dn", getpid(), getppid()); }else{//parent tempW = wait(NULL); printf("Catched a child process, pid = %d, ppid = %dn", tempW, getppid()); }//of if printf("......finish......"); return 0; }//of main
【案例 2】结果如下:
使用wait同步进程,并使用宏获取子进程的返回值。
#include#include #include 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=%dn",getpid()); exit(5); } else{//父 tempW = wait(&tempStatus); if(WIFEXITED(tempStatus)){ printf("Child process pid=%d exit normally.n", tempW ); printf("Return Code:%dn",WEXITSTATUS(tempStatus)); } else { printf("Child process pid=%d exit abnormally.n", tempW); }//of if }//of if return 0; }//of main
【案例 3】结果如下
父进程等待进程组中指定子进程,该进程不退出,则父进程一直阻塞。
#include【案例 4】#include #include int main(){ pid_t tempPid, tempP, tempW; tempPid= fork(); //创建第一个子进程 if (tempPid == -1){ perror("fork1 error"); exit(1); } else if (tempPid == 0){ //子进程沉睡 sleep(5); printf("First child process:pid=%dn", getpid()); } else { //父进程继续创建进程 int i; tempP = tempPid; for (i = 0; i < 3; i++){ //由父进程创建3个子进程 if ((tempPid = fork()) == 0){ break; }//of if }//of for i if (tempPid == -1){ //出错 perror("fork error"); exit(2); } else if (tempPid == 0){ //子进程 printf("Child process:pid=%dn", getpid()); exit(0); } else { //父进程 tempW = waitpid(tempP, NULL, 0); //等待第一个子进程执行 if (tempW == tempP){ printf("Catch a child Process: pid=%dn", tempW); }else{ printf("waitpid errorn"); }//of if }//of if }//of if return 0; }//of main
基于waitpid函数不断获取子进程的状态。
#include#include #include int main() { pid_t tempPid, tempW; tempPid = fork(); if (tempPid == -1){ perror("fork error"); exit(1); } else if (tempPid == 0){ sleep(3); printf("Child process:pid=%dn", getpid()); exit(0); } else { do{ tempW = waitpid(tempPid, NULL, WNOHANG); if (tempW == 0){ printf("No child exitedn"); sleep(1); }//of if } while (tempW == 0); if (tempW == tempPid){ printf("Catch a Child process:pid=%dn", w); }else{ printf("waitpid errorn"); }//of if }//of if return 0; }//of main
总结
经过这次学习,我初步了解了exec函数族及其包含的六个函数,wait函数和waitpid函数的功能和区别,通过代码运行后对函数作用有了简单了解,以及进程退出函数的使用,特殊进程:孤儿进程,僵尸进程的概念。



