Linux:fork函数&僵尸进程&孤儿进程

  • Post author:
  • Post category:linux




fork

创建子进程

  • pid_t fork (void)
  • 让进程在运行时调用fork创建一个新进程,该新进程称为子进程;

    fork函数没有参数

对fork理解:

  • 有一个程序,里面有一个fork函数,该程序运行后成为进程;
  • 这个函数会告诉操作系统将这个进程所有的东西都拷贝一份(这是fork函数自己的功能);

    并不是完全拷贝
  • 也就是去拷贝父进程的PCB(因为一个进程里的所有信息都在PCB中),这样就产生了一个新进程;

进程如何被运行(pcb可以放到其它结构中)

  • Linux内核中存在一个运行队列,里面放的都是一个pcb,每个pcb指向自己的代码和数据
  • 父子进程代码相同但是数据不同 。
  • 子进程pcb创建好后,执行代码后并返回一个值

fork函数有两个返回值

创建失败 返回值小于0
创建成功 返回值等于0,并返回给子进程
创建成功 返回值大于0,并返回给父进程,值为子进程的PID

父子进程代码相同的原因:

  • 这个新进程就是子进程,原进程称为父进程;
  • 在代码部分父进程和子进程是一模一样的(因为在PCB中有一个变量叫内存指针,该指针指向了一块虚拟地址,在该地址组成之一就是代码段)
  • 父子进程代码相同但是数据不同 。子进程pcb创建好后,执行代码返回一个值

子进程被父进程创建出来运行次序:

  • 子进程被父进程创建出来后,在内核中是一个PCB,该PCB就会被挂在双向链接中组织起来;
  • 父进程和子进程谁先运行不确定,取决于操作系统的调度(操作系统通过双向链表调度)
  1. 父子进程二者是抢占式执行
  2. 子进程被创建出来后,子进程的运行和父进程无关
  3. 子进程被创建出来后,从fork函数之后开始运行

为什么给父进程返回子进程pid,给子进程返回0

  • 父进程必须有标识子进程的方案
  • 子进程最重要的是要知道自己被创建成功了

    子进程的父亲是唯一的,类似二叉树的父节点

fork为什么有两个返回值

  • 如何做到:通过不同的返回值执行不同的代码

(重点)

  • 父进程调用fork完毕后,在父进程的PCB中,
  • 程序计数器保存了调用fork完毕后的下一条汇编指令;
  • 上下文信息保存了调用fork完毕后的寄存器指令,
  • 然后子进程拷贝了父进程的PCB后,会读取程序计数器和上下文信息中的内容
  • 此时就指定了子程序应该从哪运行汇编指令

在这里插入图片描述

gitpid()函数 谁调用返回谁的进程号
gitppid()函数 谁调返回谁的父进程的进程号
  • Linux命令行叫命令行解释器,也是一个进程,大部分的命令行解释器叫bash,可以称为bash进程;
  • 输入ls命令时(ls命令时一个可执行程序,运行起来就是一个进程),bash进程就会启动ls进程去完成相应的操作;
  • 也就是说在命令行解释器中启动一个进程,该进程的父进程是bash。



僵尸进程:

指先于父进程退出的子进程程序已经不再运行

但是因为保存退出原因,因此资源没有完全释放的进程,因此不会自动退出释放资源


  • 此时子进程的状态就变成僵尸状态(该子进程称为僵尸进程)
  • 对于用户来说,这个子进程已经退出了,
  • 对于操作系统而言操作系统内核还在维护着该子进程的PCB资源。



1.产生僵尸进程的原因:

  • 子进程在退出的时候会向父进程发送一个信号
  • 父进程忽略该信号

    导致子进程在退出的时候没有进程来回收子进程的资源(PCB资源)

    子进程变成了僵尸进程。



2.僵尸进程模拟:

  1. 在代码中创建一个子进程;
  2. 模拟让子进程先于父进程退出:通过fork函数让父子进程走不同的分支逻辑(子进程退出,父进程不退出);

    在这里插入图片描述



3.僵尸进程的危害:

Kill +pid

Kill -9+pid:强杀命令

  • 僵尸进程不能用上述两个命令结束;
  • 造成内存泄漏

    该进程的PCB并未释放,还存在于内存中,也就是不能从操作系统内核中释放该进程,使用强杀命令也不行。



4.解决方案:

  1. 重启操作系统;
  2. 进程等待;
  3. 将僵尸进程的父进程干掉变成孤儿进程变成Z状态的进程,可以称为僵尸进程,也可以说这种进程状态是僵尸状态



孤儿进程:

父进程创建一个子进程,父进程先于子进程退出,子进程就是孤儿进程

孤儿进程模拟:

  1. 子进程代码中写一个死循环
  2. 父进程直接退出

在这里插入图片描述

孤儿进程的父进程变成了1号进程,当子进程的父进程先退出,子进程会被1号进程所领养;孤儿进程被1号进程领养后,子进程就会变成后台进程

父进程没有变成Z的原因

  • 父进程也有父进程,父进程的父进程是bash
  • bash会自动回收它的子进程的PCB
  • 如果给自己的子进程写回收代码,那么也会被bash回收



1号进程:

  • 又称为init号进程,操作系统启动的第一个进程就是1号进程;
  • 1号进程会fork出很多进程去完成操作系统内核的工作;
  • 如果子进程父进程是1号进程,该子进程不一定是孤儿进程

在bash中执行一个程序(bash进程也有fork函数):

  • bash会创建一个子进程去完成g_fork命令,(bash子进程中也有fork函数);
  • g_fork代码中有fork函数再创建一个子进程(这个子进程相对于我们写的代码来说就是父进程);
  • 然后原bash进程会被阻塞(这个子进程对于bash而言就是一个前台进程,从而阻塞bash)。



僵尸进程与孤儿进程:

Kill掉僵尸进程的父进程,该僵尸进程就会变成孤儿进程,被1号进程领养

1号进程会回收僵尸进程的PCB资源。



进程优先级

什么是优先级

优先级是进程获取资源的先后顺序

什么是权限

进程有没有获取资源的权限

为什么存在优先级

资源不够

查看优先级:ps -l

Linux下用priority+nice值确定

nice值进程优先级的修正数据(-20~19)

数字越小,优先级越高

更改进程优先级需要改nice,而不是pri

每次设置优先级前,优先级都先会被恢复成80

用top命令或者系统调用函数修改,系统不允许用户无节制设计

Linux共140个优先级

分时操作系统

实时操作系统



版权声明:本文为qq_45481606原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。