进程的创建,等待,终止与程序替换

进程的创建

  • 进程的创建用的是fork函数
  4 int main(void){
  5     pid_t pid;
  6 
  7     printf("before :pid is %d\n",getpid());
  8     if((pid=fork())==-1){
  9     perror("fork()");
  5     pid_t pid;
  5     pid_t pid;
  6 
  7     printf("before :pid is %d\n",getpid());
  8     if((pid=fork())==-1){
  9     perror("fork()");
 10     exit(1);
 11     }
 12     printf("after:pid is %d\n",getpid());
 13     sleep(1);
 14     return 0;
**运行结果**

$ ./a.out
before :pid is 25710   //进程id
after:pid is 25710      //父进程id
after:pid is 25711      //子进程id

这里写图片描述

  • 父进程和子进程除了代码是共享的之外,其他的都是原件与副本的关系。既然是副本,就说明两个是不同的进程,有各自的虚拟内存,最后通过mmu映射到物理内存当中去。
  • 由fork又引出了vfork这一概念,vfork和fork的作用是相同的,但是不同的是它的子进程和父进程共享地址空间,。而且vfork可以保证子进程先运行

进程的终止

  • 进程退出有三种情况:运行并且结果正确;运行结果不正确;异常退出
  • 正常退出:从main函数返回,调用exit,_exit函数
  • 异常退出:Ctrl+c,信号终止
  • exit和_exit的区别:exit在退出之前会关闭所有的流,所有的缓存数据也都被写入
    完成之后才退出;_exit是直接退出

进程的等待

  • 父进程提前退出,而子进程想要报告信息给父进程找不到对象,就会进入僵尸进程,造成内存泄漏
  • 进程一旦进入了僵尸状态,就无法杀死了
  • 而父进程派给子进程的任务完成的如何,也是需要返回的
  • 所以就引出了进程等待,可以回收子进程资源,获取子进程退出信息
    以下是一个进程等待的代码
  1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<stdlib.h>
  4 #include<errno.h>
  5 #include<sys/types.h>
  6 
  7 int main(void){
  8     pid_t pid;
  9     
 10     
 11     pid=fork();
 12     if(pid==-1){
 13     perror("fork()");
 14     exit(1);
 15     }
 16 
 17     //创建子进程成功之后,等待10秒后退出
 18     if(pid==0){//子进程
 19     sleep(10);
 20     exit(10);
 21     }
 22     else{//父进程
 23     
 24     //子进程的退出分两种情况,正常与异常,这时候就需要父进程进行等待观察
 25     int st;
 26     int ret=wait(&st);
27 
 28     //若正常退出,则ret为子进程的id
 29     if(ret>0&&(st&0X7F)==0){
 30     printf("child exit code:%d",(st>>8)&0XFF);
 31     }
 32     //若异常退出,返回了-1,
 33     else if(ret<0){
 34     printf("sig code:%d\n",st&0X7F);
 35     }
 36     }

**运行结果**
./a.out
child exit code:10// 子进程正常退出
  • 进程的等待分为两种:非阻塞和阻塞;
 pid_t waitpid(pid_t pid, int *status, int options);
//options有两种取值,取0时为阻塞,WNOHANG 时为非阻塞
//WNOHANG 表示如果没有已经退出的子进程需要收集,返回0;若正常结束,则返回子进程pid

进程程序的替换

  • 用fork创建了子进程,子进程和父进程执行的是相同的代码,但是子进程往往要调用exec函数来执行自己的程序,exec函数不创建新的进程,所以进程id不会变
    这里写图片描述
  • 最终的调用都会到execve 这个函数上
  • v代表了数组,可以概括list
  • e代表了自己组装环境变量,不可以使用环境变量path,所以需要写全路径。

简易的xshell

1 #include<unistd.h>
  2 #include<stdio.h>
  3 #include<stdlib.h>
  4 #include<sys/wait.h>
  5 #include<string.h>
  6 char *argv[8]    //最多8个字符,存储命令行参数
  7 int argc=0;      //命令行参数个数
  8 //例如ps -ef 命令行参数个数为2,参数分别为 ps 和-ef
  9 
 10 //解析命令行,从buf 中判断哪些显示在命令行上,哪些不显示
 11 void parse(char *buf)
 12 {
 13     int i;
 14     int status=0;//记录是否读取命令行参数的状态
 15     
 16     for(i=0;buf[i];i++){
 17         if(!isspace(buf[i])&&status==0)//若遇到字符,则一次往后读
 18         {
 19             argv[i++]=buf+i;//将放入buf中的解析到argv中
 20             status=1;
 21         }
 22         else if(isspace(buf[i]))//若遇到空格,则不读
 23         {
 24             status=0;
 25             buf[i]=0;
 26         }
 27     }
 28     argv[i]=NULL;//已经读完
 29 }
 31 //程序替换
 32 void execute(void)
 33 {
 34     pid_t pid;
 35                                                                                                    
 36     switch(pid){
 37         case -1:
 38             perror("fork");
 39             exit(EXIT_FAILURE);
 40             break;
 41         case 0:
 42             execvp(argv[0],argv);//程序替换,数组,不需要写全路径
 43             perror("execvp");
 44             exit(EXIT_FAILURE);
 45         default:
 46             {
 47                 int st;
 48                 while(wait(&st)!=pid)//若子进程一直没结束,则父进程一直等待
 4950             }
 51     }

猜你喜欢

转载自blog.csdn.net/Ning_zhi_t/article/details/81292741