进程(2)—— wait()/waitpid()、vfork+exec

一 进程间调度—— wait()/waitpid()

进程之间的调度(如何让父进程等待子进程),wait() waitpid()就是进程之间的调度函数。

1 wait()函数

pid_t wait(int* status)
  用于父进程等待子进程的结束,如果父进程有多个子进程的话,等待任意一个子进程结束都会返回。wait的返回值pid_t 可以获取结束子进程的PID,参数status用于 返回结束子进程的状态和退出码。

  wait()可以回收僵尸子进程。
  
宏函数 WIFEXITED(status)可以判定是否正常结束
宏函数 WEXITSTATUS取退出码(exit(退出码))
(退出码后8位有效)

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>

int main(){
    pid_t pid = fork();
    if(pid==0){//子进程
        printf("子进程%d开始运行\n",getpid());
        sleep(5);  
        printf("子进程运行结束\n");
        exit(100); 
    } //退出码100
    printf("父进程开始运行\n");
    int status; pid_t pid2 = wait(&status);
    printf("成功等待子进程的结束\n");
    printf("pid=%d\n",pid2);
    if(WIFEXITED(status)){
        printf("子进程正常退出\n");
        printf("code=%d\n",WEXITSTATUS(status));
    }
    printf("父进程结束运行\n");
}

2 waitpid()函数

pid_t waitpid(pid_t pid,int* status,int option)
pid是进程的ID,可以有4种情况:
  < -1 等待 进程组ID等于参数绝对值的子进程
  -1 等待任意子进程
  0 等待 和父进程一个进程组的子进程
  大于0 等待进程ID等于参数的子进程(指定一个)

status 和 wait参数一样
  option 0 代表会一直等待直到有子进程退出(阻塞)
  WNOHANG 代表不会等待,有没有子进程退出都返回(非阻塞)

返回值有三种可能:
  返回结束子进程的PID
  如果option为WNOHANG,没有子进程结束时返回0
  出错返回 -1.

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>

int main(){
    pid_t pid1,pid2;
    pid1 = fork();
    if(pid1>0) pid2 = fork();//只有父进程fork
    if(pid1 == 0){//子进程1
        printf("子进程%d开始运行\n",getpid());
        sleep(3); 
        printf("子进程%d结束运行\n",getpid());
        exit(100); 
    }
    if(pid2 == 0){//子进程2
        printf("子进程%d开始运行\n",getpid());
        sleep(1); 
        printf("子进程%d结束运行\n",getpid());
        exit(200); 
    }
    int status;
    printf("pid1=%d,pid2=%d\n",pid1,pid2);
    pid_t pid = waitpid(-1,&status,0);
    printf("pid=%d\n",pid);
    if(WIFEXITED(status)){
      printf("code=%d\n",WEXITSTATUS(status));
    }
    printf("end\n");
}

二 vfork+exec

vfork()用法在语法上和fork()一样,区别:
  1 vfork() 不复制 父进程任何的内存空间。
  2 vfork() 确保子进程先运行。
  vfork()创建的子进程占用父进程的内存空间运行,父进程在此时被阻塞,vfork()要和 exec系列函数结合使用才有意义。vfork 负责创建子进程,exec系列函数负责提供新的程序被执行。当vfork()创建的子进程执行新的程序时,父进程的内存空间就会返回给父进程,父子进程同时运行。

经验:
  fork()创建子进程和父进程执行相同的代码。
  vfork()创建子进程 执行的代码与父进程无关,而是全新的代码。

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main(){
    pid_t pid = vfork();//fork();
    if(pid==0){//子进程
        sleep(1);
        printf("child end\n");
        exit(10);
    }
    printf("father end\n");
}

  exec系列函数不是新建一个进程,而是修改进程。用新的代码区、堆区、栈区、数据区(程序) 替换旧的。
  exec系列函数不改变 PID。

#include <stdio.h>
#include <unistd.h>

int main(){
    printf("begin\n");
    //第一个参数是程序(包括路径),第二个参数是
    //命令,第三个参数是选项,第四个参数是参数
    //345...NULL结束
    //执行ls -l /home
    //execl("/bin/ls","ls","-l","/home",NULL);
    //execlp在系统路径PATH中配置的程序省略路径
    execlp("ls","ls","-l","/home",NULL);
    printf("end\n");//不会被执行,因为新代码区
}
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>

int main(){
    pid_t pid = vfork();
    if(pid == 0){
        execlp("ls","ls","-l","/home/tarena",NULL);
       //exit(100);//exec系列函数会更换代码区
    }
    int status;
    wait(&status);
    printf("code=%d\n",WEXITSTATUS(status));
    printf("end\n");
}

创建子进程的方法有两种:
  1 fork() - 父子进程执行相同的代码段
  2 vfork()+exec系列函数 - 子进程执行完全不同的代码段。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值