Linux——进程等待和进程替换

进程等待&进程替换

  • 1.进程等待
    • 1.1进程等待的必要性
      • 1.1.1如何避免僵尸进程呢?
    • 1.2进程等待的方法
      • 1.2.1 wait
      • 1.2.2 waitpid()
        • 1.2.2.1(pid_t pid)参数(要等待的子进程的进程号)
        • 1.2.2.2(int* status)参数(退出的子进程的状态)
        • 1.2.2.3(int options)参数(设置当前的waitpid是阻塞的还是非阻塞的)
      • 1.2.3 wait和waitpid的区别
  • 2.进程替换
    • 2.1替换原理(也会发生写时拷贝)
    • 2.2替换函数(操作系统提供的六大接口)
    • 2.3函数解释
    • 2.4命名理解
    • 2.5复习插眼(为了日后复习回忆知识):

1.进程等待

1.1进程等待的必要性

  • 子进程退出,父进程如果不管不顾,就可能造成僵尸进程的问题,进而造成内存泄漏
  • 另外,进程一旦变成僵尸状态,那就刀枪不入,“杀人不眨眼”的kill -9 也无能为力,因为谁也没有办法杀死一个已经死去的进程
  • 最后,父进程派给子进程的任务完成的如何,我们需要知道。如:子进程运行完成,结果对还是不对,或者是否正常退出
  • 父进程通过进程等待的方式,回收子进程资源,获取子进程退出信息

—————————————————————————————————-------

  • 普遍情况是让子进程先退出:
  • 如果父进程先退出 ,子进程被init接管,子进程退出后init会回收其占用的相关资源
  • 如果子进程先退出,父进程又没有回收子进程,释放子进程占用的资源,此时子进程将成为一个僵尸进程。

1.1.1如何避免僵尸进程呢?

  • 父进程通过 wait 和 waitpid 等函数等待子进程结束,这会导致父进程挂起
  • 如果父进程很忙,那么可以用signal函数为SIGCHLD安装handler,因为子进程结束后, 父进程会收到该信号,可以在handler中调用wait回收
  • 如果父进程不关心子进程什么时候结束,那么可以用signal(SIGCHLD,SIG_IGN) 通知内核,自己对子进程的结束不感兴趣,那么子进程结束后,内核会回收, 并不再给父进程发送信号

1.2进程等待的方法

Linux——进程等待和进程替换_第1张图片

1.2.1 wait

Linux——进程等待和进程替换_第2张图片

  • 返回值
    成功返回被等待进程pid,失败返回-1。
  • 参数
    输出型参数,获取子进程退出状态,不关心则可以设置成为NULL

1.2.2 waitpid()

1.2.2.1(pid_t pid)参数(要等待的子进程的进程号)

Linux——进程等待和进程替换_第3张图片

1.2.2.2(int* status)参数(退出的子进程的状态)

在这里插入图片描述

  • status是一个整型指针,其实在传参的时候,该参数是一个输出型参数
  • wait和waitpid,都有一个status参数,该参数是一个输出型参数,由操作系统填充。
  • 如果传递NULL,表示不关心子进程的退出状态信息。
  • 否则,操作系统会根据该参数,将子进程的退出信息反馈给父进程
  • status不能简单的当作整形来看待,可以当作位图来看待,具体细节如下图(只研究status低16比特位):
    Linux——进程等待和进程替换_第4张图片
    Linux——进程等待和进程替换_第5张图片
    Linux——进程等待和进程替换_第6张图片

1.2.2.3(int options)参数(设置当前的waitpid是阻塞的还是非阻塞的)

WNOHANG:若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。
       :若正常结束,则返回该子进程的ID。
  • WNOHANG 非阻塞 如果在掉用非阻塞的waitpid接口的时候,如果等待的子进程没有退出,waitpid也不会等待,直接返回,执行后面逻辑
  • 非阻塞需要搭配循环去使用: 如果非阻塞的接口在调用waitpid时,没有等待到子进程退出,则循环去调用waitpid接口

1.2.3 wait和waitpid的区别

Linux——进程等待和进程替换_第7张图片
—————————————————————————————

  • wait等待的是任意一个子进程的退出(wait是一个父进程假设有很多子进程,任意一个退出,都会处理后调用返回)
  • waitpid可以等待指定的子进程,也可以等待任意一个子进程,通过第一个参数确定(第一个参数pid== -1则表示等待任意)

—————————————————————————————

  • wait是一个阻塞等待(wait如果没有子进程退出,则会一直等待)
  • waitpid可以默认阻塞,也可以设置为非阻塞,通过第三个参数确定(第三个参数 option== 0表示默认阻塞;option==WNOHANG 则表示非阻塞)

总结:

  • waitpid(pid大于0,status,0)相当于wait接口
  • wait接口实现其实就是调用waitpid实现。

2.进程替换

2.1替换原理(也会发生写时拷贝)

  • fork创建子进程:1.让子进程和执行父进程一部分代码:代码共享 2.让子进程执行和父进程完全不同的事:调用exce函数,代码也要发生写时拷贝
  • 当进程调用另外一种exce函数时,该进程的用户空间和代码和数据将完全被新程序替换,从新程序启动的例程开始执行调用exce函数并不是创建新进程,所以调用exce前后该进程的id并没有改变
    Linux——进程等待和进程替换_第8张图片

通过进程PCB当中的内存指针,找到进程虚拟地址空间当中的数据段和代码段,通过页表映射将数据段和代码段映射到新的程序的物理内存上,通俗讲,使用新的程序将之前的数据段和代码段进行更新。

程序替换是在当前进程pcb并不退出的情况下,替换当前进程正在运行的程序为新的程序(加载另一个程序在内存中,更新页表信息,初始化虚拟地址空间)

2.2替换函数(操作系统提供的六大接口)

Linux——进程等待和进程替换_第9张图片

  • 操作系统只提供了execve一个调用接口其余的五个函数都是execve的封装
    Linux——进程等待和进程替换_第10张图片

2.3函数解释

  • 这些函数如果调用成功则加载新的程序从启动代码开始执行,不再返回。
  • 如果调用出错则返回-1
  • 所以exec函数只有出错的返回值而没有成功的返回值,因为成功的话,所有数据和代码都会被覆盖

2.4命名理解

Linux——进程等待和进程替换_第11张图片
Linux——进程等待和进程替换_第12张图片

在这里插入图片描述
file:可执行程序的名称,同时这个可执行程序要能在PATH环境变量当中找到,否则程序替换就失败了;同时也可以传递一个带有路径的可执行程序
argv:要给可执行程序传递的参数,第一个参数是该程序的名称, 以NULL结尾

Linux——进程等待和进程替换_第13张图片

  • 总结:
  • l(list):表示参数采用列表
  • v(vector):参数采用数组
  • p(path):有p就自动搜索环境变量PATH
  • e(env):表示自己维护环境变量
    Linux——进程等待和进程替换_第14张图片

2.5复习插眼(为了日后复习回忆知识):

  • 1.excel(“/usr/bin/ls”,“ls”,“-l”,‘-a",NULL)之后的代码无法打印出来,因为替换成功,如果替换不成功(地址不对的情况),就会打印之后的程序

  • 2.Makefile默认只生成一个可执行程序,默认是自顶向下扫描遇到的第一个目标
    Linux——进程等待和进程替换_第15张图片

  • 3.exec系列函数调用系统的程序,也可以调用自己的程序

  • 4.传入一串字符串,通过子进程分析字符串,父进程利用while循环不断的创建子进程,创建一个子进程就等待它分析完毕,分析完毕由于子进程其它的代码被替换以致结束,而父进程外边还有while循环,所以这样生成一个不断循环的过程
    Linux——进程等待和进程替换_第16张图片

你可能感兴趣的:(Linux,进程等待,进程替换,exec函数,wait和waitpid,Linux)