【Linux】进程的理解(三)

本文主要讲解以下几个知识点:

1.进程等待

2.进程程序替换

3.实现一个简单的shell,并且认识shell的运行原理

 

 

一.进程等待

     1.首先让我们搞清楚为什么需要进程等待??

             我们知道僵尸进程是一个很可怕的东西,就算用kill -9都是干不掉的,而且僵尸进程就像是毒瘤一般会造成很大的危害(内存泄漏)。所以进程等待很大程度上就是为了避免僵尸进程的产生

     2.进程等待的必要性

  • 为了避免产生僵尸进程,造成危害
  • 父进程派给子进程的任务完成的如何,我们需要知道。例如:子进程退出后,运行的结果对还是不对,或者是否是正常退出
  • 父进程通过进程等待的方式,回收子进程资源,获取子进程退出信息

     3.进程等待的方法

        a)wait方法

wait()函数是等待任意子进程退出(阻塞式等待函数)

阻塞式调用:如果没有子进程退出,就一直等待,不返回,直到子进程退出

代码演示:

  1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<errno.h>
  4 #include<stdlib.h>
  5 #include<wait.h>
  6 int main()
  7 {
  8         pid_t pid;
  9 
 10         pid = fork();
 11         if(pid  <  0)
 12         {
 13                 perror("fork");
 14                 exit(1);
 15         }
 16         else if(pid == 0)
 17         {
 18                 sleep(10);
 19                 exit(10);
 20         }
 21         else
 22         {
 23                 int st;
 24                 int ret = wait(&st);
 25                 if(ret > 0 && (st & 0X7E) == 0)
 26                 {
                          //正常退出
 27                         printf("child exit code:%d\n",(st>>8)&0XFF);
                                                                                           
 29                 }
 30                 else if(ret > 0)
 31                 {
                            异常退出
 32                         printf("sig code:%d\n",st & 0X7E);
 33                 }
 34 
 35         }
 36         return 0;
 37 }

我们可看到sleep 10s后会进程正常退出

在这一由于xshell出了点问题没法演示异常退出,下次补上。大家可以在另一个终端执行kill命令来查看异常退出(这里自行查看) 

b)waitpid方法

可进行man手册进程查看

代码展示:

阻塞式等待:如果没有子进程退出,就一直等待,不返回,直到子进程退出

  1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<errno.h>
  4 #include<stdlib.h>
  5 #include<wait.h>
  6 int main()
  7 {
  8         pid_t pid;
  9 
 10         pid = fork();
 11         if(pid  <  0)
 12         {
 13                 perror("fork");
 14                 exit(1);
 15         }
 16         else if(pid == 0)
 17         {
 18                 printf("child is run,pid is: %d\n",getpid());
 19                 sleep(10);
 20                 exit(5);
 21         }
 22         else
 23         {
 24                 int st = 0;
 25                 int ret = waitpid(-1,&st,0);  //阻塞式等待
 26                 printf("this is test for wait\n");
 27                 if(WIFEXITED(st) && ret == pid)
 28                 {
 29                         printf("wait child success,return code is: %d\n",WEXITSTATUS(st));
 30                 }
 31                 else
 32                 {
 33 
 34                         printf("wait child falied,return \n");
 35 
 36                 }
 37         }
 38         return 0;
 39 }

非阻塞式等待:在调用没有在规定时间内接收到返回值时,立即返回。

 

  5 #include<stdio.h>
  6 #include<unistd.h>
  7 #include<wait.h>
  8 #include<errno.h>
  9 #include<stdlib.h>
 10 
 11 int main()
 12 {
 13         pid_t pid = fork();
 14 
 15 
 16         if(pid < 0)
 17         {
 18 
 19                 perror("fork");
 20                 return -1;
 21         }
 22 
 23         else if(pid == 0)
 24         {
 25                 printf("child!=> %d\n",getpid());
 26                 sleep(5);
 27                 exit(-1);
 28         }
 29         else
 30         {
 31                 int status = 0;
 32                 int ret = 0;
 33                 do
 34                 {
 35 
 36                         ret = waitpid(-1,&status,WNOHANG);
 37                         if(ret == 0)
 38                         {
 39                                 printf("child is run!!\n");
 40 
 41                         }
 42 
 43                   sleep(2);
 44                 }while(ret == 0);
 45                 if(ret == pid && WIFEXITED(status))
 46                 {
 47 
 48                         printf("success!! childexit=> %d\n",WEXITSTATUS(status));
 49                         printf("childpid!!=> %d\n",ret);
 50                 }
 51 
 52                 else
 53                 {
 54                         printf("failed!!\n");
 55                 }
 56                 printf("father!=> %d  ret=> %d\n",getpid(),ret);
 57         }
 58 
 59         return 0;
 60 }

 

注意:

  • 如果子进程已经退出,再调用wait/waitpid时,则wait/waitpid会立即退出,并且释放资源,获取子进程退出信息
  • 如果在任意时刻调用wait/waitpid时,而且子进程存在且正常运行,则进程可能阻塞
  • 如果不存在子进程则立刻报错返回

获取子进程status(进程的退出状态码):

  • wait/waitpid,都是一个status参数,该参数是一个输出型参数,由操作系统填充
  • 在wait/waitpid的参数中存储了子进程的退出原因以及退出码,虽然退出状态用了四个字节来获取,但是参数中只用了低16位两个字节用于存储这些信息

  • 在低16位中的高8位中存储退出码,程序运行完毕才会有,低8位为0

  • 在低16位中的低7位中存储的是引起异常退出的信号值,当程序异常退出时,状态码是0,高八位为0,第八位存储core dump标志

二.进程替换

1.为什么要进行进程替换??

因为我们在创建进程时,我们希望子进程去做和父进程不同的事,所以就需要进程替换

2.进程替换的特性:

  • 再调用exec替换函数后,子进程的用户空间和数据将被新的程序或者变量替换(不用开辟新的空间)
  • 在调用exec函数前后,进程ID不变
  • 在调用完exec函数后,进程将从新的入口函数执行新的程序

五个替换函数的理解请看博客:

https://blog.csdn.net/alidada_blog/article/details/82656228

 

三.实现简单的xshell

实现的功能:

1.获取命令行

2.解析命令行

3.建立一个子进程(fork)

4.替换子进程(execvp)

5.父进程等待子进程退出(wait)

代码展示:

 1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<stdlib.h>
  4 #include<errno.h>
  5 #include<string.h>
  6 #include<ctype.h>
  7 
  8 char *argv[8];
  9 
 10 int argc = 0;
 11 void  do_parse(char* buf)
 12 {
 13         int status = 0;
 14         int i = 0;
 15         for(argc = i = 0;buf[i];i++)
 16         {
 17                 /*
 18                  *isspace检测空格的函数,如果有空格则输出ture,不是空格返回0
 19                  *
 20                  *
 21                  * */
 22 
 23                 if( !isspace(buf[i]) && status == 0)
 24                 {
 25                         argv[argc++] = buf + i;
 26 
 27                         status = 1;
 28 
 29 
 30                 }
 31                 else if(isspace(buf[i]))
 32                 {
 33                         buf[i] = 0;
 34                         status = 0;
 35 
 36                 }
 37 
 38         }
 39 
 40         argv[argc] = NULL;
 41 }
 42 
 43 
 44 //对进程的操作函数
 45 void do_execute()
 46 {       
  1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<stdlib.h>
  4 #include<errno.h>
  5 #include<string.h>
  6 #include<ctype.h>
  7 
  8 char *argv[8];
  9 
 10 int argc = 0;
 11 void  do_parse(char* buf)
 12 {
 13         int status = 0;
 14         int i = 0;
 15         for(argc = i = 0;buf[i];i++)
 16         {
 17                 /*
 18                  *isspace检测空格的函数,如果有空格则输出ture,不是空格返回0
 19                  *
 20                  *
 21                  * */
 22 
 23                 if( !isspace(buf[i]) && status == 0)
 24                 {
 25                         argv[argc++] = buf + i;
 26 
 27                         status = 1;
 28 
 29 
 30                 }
 31                 else if(isspace(buf[i]))
 32                 {
 33                         buf[i] = 0;
 34                         status = 0;
 35 
 36                 }
 37 
 38         }
 39 
 40         argv[argc] = NULL;
 41 }
 42 
 43 
 44 //对进程的操作函数
 45 void do_execute()
 46 {
 47         pid_t pid = fork();
 48 
 49         if(pid < 0)
 50         {
 51                 perror("fork");
 52                 exit(0);
 53         }
 54         else if(pid == 0)
 55         {
 56                 execvp(argv[0],argv);
 57                 perror("execvp");
 58                 exit(0);
 59         }
 60         else
 61         {
 62                 int st;
 63                 int ret = wait(&st);
 64                 while(ret != pid);
 65 
 66 
 67         }
 68 
 69 
 70 }
 71 
 72 
 73 int main()
 74 {
 75 
 76         char buf[1024] = {};
 77         while(1)
 78         {
 79                 printf("myshell=> ");
 80                 scanf("%[^\n]%*c",buf);
 81 
 82                 do_parse(buf);
 83                 do_execute();
 84         }
 85 
 86         return 0;
 87 }

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值