0
点赞
收藏
分享

微信扫一扫

Flink1.18 如何配置算子级别的TTL

登高且赋 03-23 09:00 阅读 5

进程的独立性

进程:内核相关管理数据结构(pcb+地址空间+页表)+代码+数据
当fork函数创建一个子进程时,如何保证进程具有独立性?
父进程的数据以及代码来自磁盘,而子进程的代码是共享父进程的,至于数据,如果子进程不修改数据的话,同样也是和父进程共享的,而如果子进程要修改数据,就会发生写时拷贝,保证数据的独立性,子进程的退出也不会对父进程做干扰.父进程退出也不会对子进程做干扰.

frok函数的返回值

子进程给父进程返回自己的pid,父进程给子进程返回0,这样是为了对子进程进行标识,进而进行管理.这个在之前的文章中有讲过

进程的终止

进程终止做了什么

1.释放曾经的代码和数据所占的空间。
2.释放内核的数据结构(pcb+地址空间+页表)
当时当子进程退出后,父进程还没有获取到子进程的状态时,子进程的代码和数据已经被释放,而内核中的数据结构还没有被释放。因为子进程的内核数据结构pcb中保存了子进程的退出码和退出信号,需要等待父进程获取.

进程终止的3种情况

1.代码跑完,结果正确
2.代码跑完,结果错误
3.代码执行时,出现了异常,提前退出了


下面看一段程序,这段程序代码会跑完,结果也正确
在这里插入图片描述

这段程序中的return 0表示什么呀?
其实这个进程相当于bash的子进程,而main函数return的是该进程的退出码,该子进程会将该退出码返回给bash,因为bash要知道子进程退出的情况,给用户提供失败的原因是什么,对用户负责.
这个退出码 可以通过指令

0就是这个程序的退出码,一般success表示成功

strerror

针对上面的错误码的话,对计算机而言,他知道退出码0,1,2,3对应着什么,我们可以通过strerror函数查看对应的退出码对应的是什么错误
在这里插入图片描述

在这里插入图片描述
退出码:0成功
!0失败
不同的非0值一方面表示失败,另一方面表示失败的原因,而对于计算机可以将退出码和错误做对应,如果我们想知道退出码对应的错误,就可以通过strerror函数来确定,对应的退出码都有错误描述string


退出码

如果我们将退出码设置为1的话
在这里插入图片描述

![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/f6fbc9c3a4e2433f8e0ab940fb90b062.png

为什么第一次获取到的退出码是1,然后使用pwd进程后,在获取退出码的时候就变成0了呢?
其实父进程bash获取到的,是最近一个子进程退出的退出码,也就是说最后的0的退出码是pwd进程执行成功给bash的退出码,需要告诉父进程,子进程把任务完成的怎么样了


退出码可以使用默认,也可以自己定义
在这里插入图片描述
枚举类型:0表示成功,1表示除0,2表示模0,exit_code为退出码,刚开始让他=0表示成功.
然后Div函数里面如果分母为0了,就说明除0了,就把他的退出码修改成1;
在这里插入图片描述

打印退出码和退出码对应的信息,这里已经打印,就不用通过bash查看退出码了
在这里插入图片描述


退出信号

针对进程终止的前两种情况。我们可以通过系统或者自定义的退出码来确定。而针对于第三种,程序出现异常,在vs中,编译运行的时候,就会崩溃,原因是操作系统发现你做了不该做的事情,操作系统杀死了进程,一旦出现异常,退出码就没有任何意义了
下面展示代码演示代码出现异常
在这里插入图片描述

当对空指针解引用并赋值100时,会出现段错误,出现野指针问题.
在这里插入图片描述

而段错误在信号类型属于11号信号
在这里插入图片描述

进程出现异常本质是因为进程收到了os发给进程的信号

所以进程的终止,我们只需要两个信息,一个是退出码,一个是退出信号,
先确定是否异常,如果不是异常,就是代码跑完了,看退出码就可以了

退出码退出信号程序
00程序跑完,结果正确
!00程序跑完,结果不正确
!0!0异常
0!0异常

进程如何终止

1.main函数中的return 表示进程终止(非main函数,return表示函数结束)
2.crrl+c (异常终止)
3.exit函数,_exit函数(正常终止)

exit函数

#include<stdlib.h>
void exit(int status);

exit函数中的参数status是退出码,exit函数不管在程序的任何一个位置,只要到了exit的话,就表示进程要终止了,而return只有在main函数里面的表示进程要结束了,其他调用函数里面return只能说明函数结束.
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/bcae315200134efcbde59130940c73e8.png

在这里插入图片描述

_exit函数也是退出进程,基本上和exit的功能一样

#include <unistd.h>
void _exit(int status);

exit函数和_exit函数的区别和联系

区别联系
exit是库函数,而_exit是系统调用,exit会冲刷缓冲区,_exit不会冲刷缓冲器两者都会结束进程

这里的缓冲区不是内核缓冲区,因为操作系统的内核缓冲区在系统调用底层,如果是内核缓冲区的话,_exit也会冲刷缓冲区,作为库函数exit会调用_exit

验证exit会冲刷缓冲区,而_exit不会:
在这里插入图片描述

在这里插入图片描述
helloworld会立刻打印出来是因为exit会冲刷缓冲区
在这里插入图片描述

在这里插入图片描述
helloworld没有打印出来,是因为helloworld此时在缓冲区
在这里插入图片描述

进程等待

概念

任何子进程,在退出的情况下,一般必须要被父进程进行等待,进程在退出的时候,如果父进程不管不顾,退出进程,子进程会出现僵尸状态,导致内存泄露.

为什么要进程等待

1.父进程通过等待,解决子进程退出的僵尸问题,回收系统资源(必须)
2.获取子进程的退出信息,知道子进程是因为什么原因退出的(选择)

怎么实现进程等待(通过wait/waitpid)

代码演示

#include<stdio.h>
   #include<stdlib.h>
   #include <unistd.h>
   #include<sys/types.h>
   #include<sys/wait.h>
   void childrun()//5秒子进程退出
   {
   int cnt=5;
   while(cnt)
  {
  printf("i am child process,pid:%d,ppid:%d,cnt:%d\n",getpid(),getppid(),cnt);
  sleep(1);
  cnt--;
  }
  }
  int main()
  {
  printf("i am father, pid:%d,ppid:%d\n",getpid(),getppid());
  size_t id=fork();
  if(id==0)
  {childrun();                                                                
    printf("child quit ...\n");//提示子进程退出
    exit(0);//子进程退出
  }
  sleep(10);//等待10秒是为了让查看状态看到子进程退出后处于的僵尸状态
  int  rd=wait(NULL);//rd就是等待的子进程的pid
  if(rd>0)
  {
  printf("wait success,rd:%d\n",rd);
  }
  }


在这里插入图片描述
rd是子进程的pid,然后子进程的资源被回收,就不会引起内存泄漏.
如果子进程没有退出,父进程其实一直在进行阻塞等待,子进程本身就是软件,父进程本质上在等待某种软件条件就绪,父进程阻塞等待子进程,就会将父进程的pcb连接到子进程的运行队列里面去,直到子进程退出,父进程会将获取子进程pcb里退出号,以及退出信号,然后父进程会回收子进程pcb资源.

获取子进程status

wait和waitpid,都有一个status参数,该参数是一个输出型参数,由操作系统填充。
如果传递NULL,表示不关心子进程的退出状态信息。否则,操作系统会根据该参数,将子进程的退出信息反馈给父进程。status不能简单的当作整形来看待,可以当作位图来看待,具体细节如下图(只研究status低16比特位):
在这里插入图片描述

(status>>8)&0xFF //取次低8位退出号
status&0x7F //取低7位退出状态
#include<stdio.h>
   #include<stdlib.h>
   #include <unistd.h>
   #include<sys/types.h>
   #include<sys/wait.h>
   void childrun()//5秒子进程退出
   {
   int cnt=5;
   while(cnt)
  {
  printf("i am child process,pid:%d,ppid:%d,cnt:%d\n",getpid(),getppid(),cnt);
  sleep(1);
  cnt--;
  }
  }
  int main()
  {
  printf("i am father, pid:%d,ppid:%d\n",getpid(),getppid());
  size_t id=fork();
  if(id==0)
  {childrun();                                                                
    printf("child quit ...\n");//提示子进程退出
    exit(0);//子进程退出
  }
  sleep(10);//等待10秒是为了让查看状态看到子进程退出后处于的僵尸状态
  int  rd=waitpid(-1,NULL,0);//rd就是等待的子进程的pid
  if(rd>0)
  {
  printf("wait success,rd:%d\n",rd);
  }
  }

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

情况1正常退出

#include<stdio.h>
   #include<stdlib.h>
   #include <unistd.h>
   #include<sys/types.h>
   #include<sys/wait.h>
   void childrun()//5秒子进程退出
   {
   int cnt=5;
   while(cnt)
  {
  printf("i am child process,pid:%d,ppid:%d,cnt:%d\n",getpid(),getppid(),cnt);
  sleep(1);
  cnt--;
  }
  }
  int main()
  {
  printf("i am father, pid:%d,ppid:%d\n",getpid(),getppid());
  size_t id=fork();
  if(id==0)
  {childrun();                                                                
    printf("child quit ...\n");//提示子进程退出
    exit(0);//子进程退出
  }
  sleep(10);//等待10秒是为了让查看状态看到子进程退出后处于的僵尸状态
  int status=0;
  int  rd=waitpid(id,&status,0);//rd就是等待的子进程的pid
  if(rd>0)
  {
  printf("wait success,rd:%d exit_code:%d exit_singal:%d\n",rd(status>>8)&0xFF,status&0x7f); 
  }
  }

在这里插入图片描述

在这里插入图片描述

情况2 9号信号验证

将上述代码子进程改成死循环
在这里插入图片描述

情况3 11号信号验证

在这里插入图片描述

将子进程中的循环改成cnt,然后将之前的段错误的代码加到子进程中去

举报

相关推荐

0 条评论