2.1 进程介绍

1 进程的创建

  1. 通过 fork 克隆调用进程
  2. 通过 execve

2 进程的终止

进程退出的原因:

  1. 正常退出
  2. 异常退出
  3. 致命错误
  4. 被杀死

3 进程的层次

进程组:一个进程及其所有深层后代构成的整体。

信号相关:发送给一个进程的信号,可以传递到相关的进程组的所有成员。

在 MINIX 中有两个特殊的进程:

轮回服务器(reincarnation server):提供服务器和驱动的重启。

初始化(init):执行 /etc/init 脚本,使其向轮回服务器发出命令,从而启动引导映像中不存在的驱动程序和服务器。如果其中某些进程中止,再生服务器就会重启,从而增加 MINIX 系统的容错性。

(例子:用户登录的过程)

完成此操作后,init 会读取配置文件 /etc/ttytab 以查看存在的终端。 init fork 为每个进程创建一个 getty 进程,在其上显示登录提示,然后等待输入用户名。用户名输入后,getty 会通过 exec 启动 login 进程,将用户名作为参数。如果用户登录成功,login 将执行用户的 shell。所以 shell 是 init 的子进程。 用户的命令创建的 shell 的子进程是 init 的孙子进程。

4 进程的状态

  1. Running:占有 CPU
  2. Ready:可以运行,但是需要等 CPU 空出
  3. Block:必须等待外部事件发生,才可运行。

image-20210901234713485

可以分为两种调度关系:

  • 1,4 由用户或特殊原因引起
  • 2,3 由系统调度引起

例子:

cat chapter1 chapter2 chapter3 | grep tree

此命令会运行 cat 和 grep。如果 cat 的输出一直没有到来,则 grep 会阻塞

阻塞的两种情况

  1. 因为用户原因,程序所固有的。如等待输入。
  2. 因为系统原因,被迫的。如 CPU 被调配给另一个进程。

5 进程的实现

进程表:含有进程表项(进程控制块,process control block,entry)。

进程表项:包含进程状态、PC、SP、内存分配情况、打开文件、统计调度信息、定时器和其它信号、调度所需的现场数据等。

在 MINIX 中,进程表是分布式的,分散到内核、进程管理、文件管理三个模块中,各自负责一部分的字段.

在内存中,维护着一个 中断描述符表(Interrupt Descriptor Table,IDT),每个中断表项,会关联到一个指向对应 中断服务器 的入口地址

中断服务程序开始时,会将所有寄存器保存在当前进程的进程表条目中。

而当前进程号和指向其表项的指针保存在全局变量中,以便定位。

然后将中断存放的信息从堆栈中移除,并将堆栈指针设置为进程处理程序使用的临时堆栈。诸如保存寄存器和设置堆栈指针之类的操作甚至无法用 C 等高级语言表达,因此它们由一个小型汇编语言例程执行。当这个例程完成时,它调用一个 C 程序来为这个特定的中断类型做剩下的工作。

MINIX 3 中的进程间通信是通过消息进行的,所以下一步是构建一条消息发送给磁盘进程。磁盘进程将被阻塞,等待消息。

该消息用于通知发生了中断,以将其与用户进程的消息(请求读取磁盘块的消息)等区分开来。

此时,磁盘进程的状态从阻塞变为就绪,然后调度程序启动。在 MINIX 3 中,不同的进程具有不同的优先级。如果磁盘进程现在是最高优先级的,并且就绪,它就会被调度运行。

如果被中断的进程同样重要或更重要,那么它将被安排再次等待调度运行,磁盘进程将不得不等待一段时间。

无论哪种方式,由汇编语言中断代码调用的 C 过程会返回,然后汇编语言代码会加载恢复当前进程的寄存器、内存映射,并启动它运行。

中断发生后调度器干了什么:

  1. 硬件 压栈 PC 等
  2. 硬件 从中断向量加载新的 PC
  3. 汇编程序 保存寄存器
  4. 汇编程序 建立新栈
  5. C 中断服务 构造并发送消息
  6. 消息传递代码 标记等待消息接收者准备好
  7. 调度程序决定接下来运行哪个进程
  8. C 程序返回到汇编代码
  9. 汇编程序启动新的当前进程

6 线程

在传统操作系统中,每个进程都有一个地址空间和一个控制线程。若是开启新的进程,则新旧进程是隔离的。我们想要让两个控制线程共享一个地址空间,于是就有了线程。线程是一种轻进程(lightweight processes)。

可以这么看:进程是一个包含资源的执行线程,简称线程。线程有一个 PC,一组寄存器和栈。进程用来集合资源,而线程是 CPU 中调度的实体。

而一个进程可以包含多个线程,从而各个线程拥有相同的进程环境。

为了实现多线程,就要有一个单独的线程表。要保存的内容包括 PC、寄存器和状态。然后线程可以处于运行、就绪和阻塞状态。

线程的实现有用户级和系统级两种。

前者,操作系统感受不到线程的存在,换言之线程由用户程序自行维护。切换速度快。

后者,操作系统可以知道有哪些线程,并且进行调度。切换速度慢。

线程的实现需要处理很多脏活。包括共享数据、错误、信号、堆栈等的处理。

2.2 进程间通信

进程间通信涉及三方面:

  1. 信息的传递
  2. 临界区的保护
  3. 活动次序