进程的终止、等待、替换

155 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 13 天,点击查看活动详情


进程终止

进程终止的时候,操作系统都做了什么?

很显然操作系统回收进程的资源。

进程终止的常见方式

  1. 代码跑完,结果正确
  2. 代码跑完,结果不正确
  3. 代码没有跑完,程序奔溃

这里的结果就是代码终止返回的退出码,可以根据退出码进行其他的操作, 一般情况下,在代码跑完的情况下,0表示结果正确,非0表示结果错误。

main函数中的return 0

return 0,就是返回一个退出码

用代码如何终止一个进程?

  1. main函数中return
  2. exit函数,也可以用系统接口_exit

他俩是有区别的,exit会刷新缓冲区,而_exit不会刷新缓冲区。本质上是在内核里面没有缓冲区这个概念

进程等待

一个进程终止了,那么它的父进程就要对他进行回收。 如何进行回收呢? 父进程是通过进程等待的方式,回收子进程的资源,获取子进程退出的信息的。 父进程可以通过这两个系统调用函数进行回收wait``waitpid

wait

image.png 成功则返回被等待进程的pid,失败则返回-1

waitpid

  • pid:pid=-1,等待任意一个进程,pid>0,等待其进程的id和pid相等的子进程
  • stat_loc:若子进程正常退出,则为真,值为0。若发生错误,则可以提取子进程的退出码 对于stat_loc后16位的前8位表示退出状态(退出码),0表示正常退出,非0表示不正常退出。 后7位表示终止信号,0表示正常运行结束,非0就是有问题。那么前8位的退出状态也就没有意义。 关于子进程有没有正常结束可以用WIFEXITED(stat_loc),若为正常终止的进程,该值为真。 若为真,用WEXITSTATUS(stat_loc)提出退出码。非真,可以下面的方法提出子进程接收到的信号。
  • options:当它为0的时候,阻塞等待子进程结束。当它为ANOHANG(1)的时候,表示非等待阻塞 如果子进程没有结束,waitpid返回0,如果结束,返回子进程的pid。
  • 问题:父进程可以通过wait/waitpid拿到子进程的退出结果,为什么要用wait、waitpid函数呢?

直接用全局变量不行吗?答案是是不可以,进程有独立性,改变的时候就会发生写实拷贝,父进程无法拿到,除此之外,信号也无法拿到。 wait/waitpid是系统调用,可以获得僵尸进程中pcb的信息。

进程程序替换

什么是进程程序替换

通过特定的接口,把磁盘上的程序完全替换到该进程中。 比如:用fork创建了一个子进程,子进程完全执行另一个程序。这就是替换。把进程替换成另一个进程。 这样的接口有好几个 image.png 先讲解一下execl是怎么用的, execl:path是那个程序的路径,arg为程序名,是可变参数列表,也就是说后面可以继续添加参数选项,当最后一个要为NULL。 当execl发生错误的时候会返回1。正常就没有返回值——因为替换成功,原进程就没有了,返回值没有意义,只有失败的时候,返回值才有意义。

详细说一下进程是怎么替换的

一个进程要想运行,那么要被加载到内存,也就是说execlk可以把进程加载到内存。又因为是替换,那么被替换的那个进程的pcb,进程地址空间,以及页表中的内容都要被替换,替换之后,原来的进程不复存在。替换的进程从新开始从main函数开始执行。

上面的方式可以在vim下进行整体替换。 image.png

  • execlp第一个参数表示程序的名字,后面的是选项。若程序名不带路径,则在默认路径,环境变量中去找。

  • execle第一个参数是路径,后面是选项,最后一个是环境变量。

  • execv第一个参数是路径,后面是指针数组,存储的是选项字符串。

  • execvp第一个参数是程序名,后面是指针数组。

  • execvpe第一个参数是程序名,后面是选项构成的指针数组,最后一个是环境变量。