子进程的产生与回收(fork与waitpid)

题目描述

父进程fork 3 个子进程,三个子进程一个调用ps命令, 一个调用自定义程序1(正常),一个调用自定义程序2(会出错误)。父进程使用waitpid对其子进程进行回收。

题目解析

此题目实际上是对前面将的例程的一个组合实现。创建3个子进程直接套用框架即可。

然后对于每一个子进程,它们的i的值是不同的,当然这三个进程实际上创建时间几乎一样而可能会出现抢夺时间片的情况,所以为了条例对三个进程分别睡眠了1秒钟、2秒钟、3秒钟,让i=0时候创建出来的子进程睡眠1秒钟,让i=1时候创建出来的子进程睡眠2秒钟,以此类推,这样保证的输出的先后顺序。

第一个子进程调用ps命令输出,因为ps是PATH里面有的路径里面的,所以可以直接执行:

execlp("ps","ps","aux",NULL);

第二个子进程既然自定义一个正常的程序,那就输出ls-l吧,所以执行

execlp("ls","ls","-l",NULL);

第三个子进程既然要输出一个出错,那么就随便执行一个不存在的东西即可,所以执行

int ret = execl("/home/xiaoao/haha","hahah",NULL);

由于第三个子进程要出错,而第一、二个子进程不能出错,所以前两个我就没有写判断错误的信息(正常程序是需要写的),只在第三个写了判断,这是利用了exec函数族只在错误的时候返回-1,其它时候不返回参数的特点。

对于父进程来说,它不会break(),所以当i=3的时候才会执行父进程,可以使用else语句直接,也可以使用else if(i==3)。一定要记住,为了回收子进程,不能使用wait语句,因为我这里虽然写了sleep时间,没有循环语句,知道多久程序运行完,但是大多数情况是不知道的,使用wait就直接阻塞在那里了。这个时候我们就需要使用轮询的方式来逐一结束子进程。该方式模板在课程里面也有说,所以不单独摘出来讲了。

另外为了方便,每个子进程我都输出了它和它父进程的PID,在父进程执行完毕的时候输出了Clean finished的提示语。

代码实现

#include <stdlib.h>#include <stdio.h>#include <unistd.h>int main(){ int n = 3; int i; pid_t pid; pid_t wpid; for(i = 0;i< n; i++) { pid = fork(); if(pid == -1) { perror("Fork error:"); exit(1); } if(pid == 0) break; } //以上就算产生了三个子进程 //对第一次循环fork出来的子进程操作 if(i == 0) { sleep(1); printf("I am %d child process, my pid is %d\n",i+ 1,getpid()); printf("And my parent process pid is %d\n",getppid()); execlp("ps","ps","aux",NULL); } //对第二个子进程调用自定义程序1 else if(i == 1){ sleep(2); printf("I am %d child process, my pid is %d\n",i+ 1,getpid()); printf("And my parent process pid is %d\n",getppid()); execlp("ls","ls","-l",NULL); } //第三个子进程,问题进程 else if(i == 2){ sleep(3); printf("I am %d child process, my pid is %d\n",i+ 1,getpid()); printf("And my parent process pid is %d\n",getppid()); int ret = execl("/home/xiaoao/haha","hahah",NULL); if(ret == -1) { perror("execl error:"); exit(1); } } //父进程,回收所有子进程 else if(i == 3){ do { wpid = waitpid(-1, NULL, WNOHANG); if(wpid > 0) n--; sleep(1); }while(n > 0); printf("Clean finished!\n"); sleep(6); } return 0;}