复习文件描述符(指向结构体的指针)
exec函数族
fork创建子进程后执行的是和父进程相同的程序(但是有可能执行不同的代码分支)子进程往往要调用一种exec函数以执行另外一个程序,当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替代,从新程序的启动例程开始执行,调用exec并不创建新的进程,所以调用exec前后进程的ID并未改变。
重点掌握
execlp函数
加载一个进程,借助PATH环境变量
int execlp(const char *file, const char *arg, …);
参数1 要加载的程序的名称该函数要配合PATH环境变量来使用,当PATH中所以目录搜索后没有参数1时则出错返回
该函数通常用来调用系统程序如:ls date cp cat 等命令
#include<stdio.h>
2 #include<stdlib.h>
3 #include<unistd.h>
4 int main(void)
5 {
6 pid_t pid;
7 pid = fork();
8 if(pid == -1){
9 perror("fork error");
10 exit(1);
11 }else if(pid > 0)
12 {
13 sleep(1);
14 printf("parent\n");
15 }else{
16 execlp("ls","ls","-l",NULL);
17 /*函数使用的参数几点注意①第一个参数是可执行程序名 ②必须以NULL结尾③对第二个参数没有要求*/
18 }
19 return 0;
20 }
补充 命令行参数
描述命令行参数的个数 argc
命令行参数的数组 argv
execl 函数
加载一个进程 通过路径+程序名
execl("/bin/ls","ls","-l",NULL);
execv函数
/*其它部分相同*/
char *argv[] = {"ls","ls","-l",NULL};
execv("/bin/ls",argv);
练习:将当前系统中的信息打印到文件中 主要open dup2 execlp 函数
dup2函数:完成文件描述符的拷贝
#include<unistd.h>
#include<fcntl.h>
#include<stdio.h>
#include<stdlib.h>
int main(void)
{
int fd;
fd = open("ps.out",O_WRONLY|O_CREAT|O_TRUNL,0644);
if(fd < 0){
perror("open ps.out error");
exit(1);
}
dup2(fd, STDOUT_FILENO); //dup2(3,1) fd stdout
execlp("ps","ps","ax",NULL);
perror("exec error");
exit(1); //出错处理
return 0;
}
总结 exec函数一旦调用成功即执行新的程序不返回,只有失败才返回-1所以通常我们直接在exec函数调用后直接调用perror()和exit()无需if判断
回收子进程
孤儿进程
父进程先于子进程结束,则子进程成为孤儿进程,子进程的父进程成为init进程 称为init进程领养孤儿进程
僵尸进程
进程终止,父进程尚未回收,子进程残留资源(PCB)存放在内核中,变成僵尸进程。
Wait函数
三个功能:
①阻塞等待子进程退出
②回收子进程残留资源
③获取子进程结束状态
pid_t wait(int *status);注意是传出参数,需要定义一个变量接受它。成功:清理掉子进程的ID,失败:-1
可借助wait函数传出参数status来保存进程的退出状态。借助宏函数来进一步来判断进程终止的具体原因
1 WIFEXITED( status) 为非0 进程正常结束
WEXITSTATUS(status) 如果上宏为真,实用此宏可以获取进程退出状态(exit的值)
2 WIFSIGMALED(status) 非0 进程异常终止
WTERMSIG(status) 如果上宏为真,实用宏取得使进程终止的那个信号的编码
//主要部分
if( WIFEXITED( status)){
printf("child exit with %d\n",WEXITSTATUS(status);
}if(WIFSIGMALED(status)){
printf("child killed by %d\n",WTERMSIG(status));
}
回收多个子进程用循环
一次wait或waitpid调用只能清理一个子进程,清理多个子进程应使用循环
while(wait(NULL))
;
//或者
while(waitpid(-1,NULL,0)); // 参3 为0时阻塞状态
不同点 第三个参数 WNOHANG 会探测子进程是否结束,为非阻塞状态,轮循结构使用do while
int n = 5 //子进程个数
pid_t wpid;
do{
wpid = waitpid(-1,NULL,0);
if(wpid > 0){
n--;
}
sleep(1);
}while(n > 0);