进程
进程模型
操作系统中最核心的概念是进程:这是对正在运行程序的一个抽象。
一个进程就是一个正在执行程序的实例,包括程序计数器、寄存器和变量的当前值。
在多道程序设计中,一个CPU能在多个进程之间来回快速切换,达到(伪)并行效果。
一个进程是某种类型的一个活动,它有程序、输入、输出以及状态。
单个处理器可以被若干进程共享,它使用某种调度算法决定何时停止一个进程的工作,并转而为另一个进程提供服务。
进程创建
以下四种事件可以触发进程创建:
- 系统初始化
- 执行了正在运行的进程所调用的进程创建系统调用(syscall)
- 用户请求创建一个新进程
- 一个批处理作业的初始化。
新进程一般都是由于一个已存在的进程执行了创建进程的系统调用而创建。
进程终止
以下四种事件可以触发进程终止:
- 正常退出(自愿的) :进程正常完成其工作而终止。
- 出错退出(自愿的) :比如用户输入命令行时,输入一个错误参数等。
- 严重错误(非自愿的): 出现非法指令,引用不存在的内存,除数为零时,段错误(page fault)等等。
- 被其他进程杀死(非自愿的):其让他进程通过调用系统调用,kill掉进程。
进程层次
在UNIX中。一个进程和它创建的进程(即子进程)构成了一颗进程树,如下图。
UNIX在启动时会先运行一个init进程,由init进程创建新进程,最终形成了进程树,所以在整个系统中,所有的进程都是以init为根节点的进程树的成员。
每个进程和它的子进程共同组成一个进程组。发给该进程组的信号可以被进程组中的进程分别捕捉。
进程状态
- 运行态(此进程实际占用CPU)
- 就绪态(可运行,但因其他进程正在运行而暂时停止)
- 阻塞态(除非某种外部事件发生,否则进程不能运行)
进程的实现
系统(一般是内核)维护着一张进程表(process table)。
每个进程占一个表项,即进程控制块(Process Control Block)。
进程控制块(PCB)包含了进程状态的重要信息。如下
利用PCB可以在发生中断时把进程状态的相关信息记录下来,让下次运行该进程的时的状态与上次中断时的状态一致。就如下图的过程1。
线程
线程模型
进程的模型可以归纳为
- 资源分组处理
- 执行
资源分组处理的体现就是进程控制块(Process Control Block)。
执行的体现就是线程。
进程与线程的关系可以在下图体现:
下面这个图展示出了线程共享和线程独占的内容。
线程和进程的区别
调度 :在引入线程的操作系统中,线程是调度和分配的基本单位 ,进程是资源拥有的基本单位 。把传统进程的两个属性分开,线程便能轻装运行,从而可显著地提高系统的并发程度。 在同一进程中,线程的切换不会引起进程的切换;在由一个进程中的线程切换到另一个进程中的线程时,才会引起进程的切换。
并发性 :在引入线程的操作系统中,不仅进程之间可以并发执行,而且在一个进程中的多个线程之间亦可并发执行,因而使操作系统具有更好的并发性,从而能更有效地使用系统资源和提高系统吞吐量。
拥有资源 :不论是传统的操作系统,还是设有线程的操作系统,进程都是拥有资源的一个独立 单位,它可以拥有自己的资源。 一般地说,线程自己不拥有系统资源(只有一些必不可少的资源),但它可以访问其隶属进程的资源。
系统开销: 由于在创建或撤消进程时,系统都要为之分配或回收资源,因此,操作系统所付出的开销将显著地大于在创建或撤消线程时的开销。 进程切换的开销也远大于线程切换的开销。
线程实现
两种方法:
- 在用户空间
-
在内核空间
用户级线程
基本结构:
- 整个操作系统分为两个部分,内核空间和用户空间,进程当时是分布在内核空间中,在进程内部定义一个运行时系统,这个运行时系统维护线程管理过程,多线程运行在这个运行时系统的基础之上。
- 每个进程有其专用的线程表,用来跟踪该进程中的线程。该表由运行时系统管理。当线程阻塞后,进程调用一个运行时系统的过程来检测是否需要进入阻塞。如果是则,它在线程表中保存状态信息,查看表中的就绪线程,并试图启动它。
优点:
- 可以在不支持线程的操作系统上实现。
- 由于线程调度时不需要陷入内核,调用都是本地调用,速度要比内核实习的快一个数量级左右
- 允许每个进程有自己定制的调度算法。
缺点:
- 一个线程陷入阻塞,就意味着所属进程的所有线程都阻塞了。
- 因为线程调度不进入内核,所以无法获取时钟中断,所以进程内的一个线程不主动放弃CPU,同进程的其他线程是无法获取CPU使用权的。
内核级线程
基本结构:
- 线程的创建、撤销和切换等,都需要内核直接实现,即内核了解每一个作为可调度实体的线程。
- 这些线程可以在全系统内进行资源的竞争。
- 内核空间内为每一个内核支持线程设置了一个线程控制块(PCB),内核根据该控制块,感知线程的存在,并进行控制。
- 在一定程度上类似于进程,只是创建、调度的开销要比进程小。有的统计是1:10
优点:
- 不需要任何新的、非阻塞的系统调用;
- 当有多个处理机时,一个进程的多个线程可以同时执行。
缺点:
- 由内核进行调度,如果线程的操作比较多,就会带来很大的开销。
进程间通信
进程间通信(Inter Process Communication,IPC)简要的说有三个问题:
- 一个进程如何把信息传递给另一个。
- 确保两个或更多的进程在关键活动中不会出现交叉。
- 保证进程以正确的顺序执行。
进程间通信的方式
无名管道
它是半双工的(即数据只能在一个方向上流动),具有固定的读端和写端。
它只能用于具有亲缘关系的进程之间的通信(也是父子进程或者兄弟进程之间)。
-
它可以看成是一种特殊的文件,对于它的读写也可以使用普通的read、write 等函数。但是它不是普通的文件,并不属于其他任何文件系统,并且只存在于内存中。
命名管道(FIFO)
它是一种文件类型。
FIFO可以在无关的进程之间交换数据,与无名管道不同。
FIFO有路径名与之相关联,它以一种特殊设备文件形式存在于文件系统中。
消息队列
是消息的链接表,存放在内核中。一个消息队列由一个标识符(即队列ID)来标识。
消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级。
消息队列独立于发送与接收进程。进程终止时,消息队列及其内容并不会被删除。
消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取。
信号量(semaphore)
它是一个计数器。信号量用于实现进程间的互斥与同步,而不是用于存储进程间通信数据。
信号量用于进程间同步,若要在进程间传递数据需要结合共享内存。
信号量基于操作系统的 PV 操作,程序对信号量的操作都是原子操作。
每次对信号量的 PV 操作不仅限于对信号量值加 1 或减 1,而且可以加减任意正整数。
支持信号量组。
共享内存
指两个或多个进程共享一个给定的存储区。
共享内存是最快的一种 IPC,因为进程是直接对内存进行存取。
因为多个进程可以同时操作,所以需要进行同步。
信号量+共享内存通常结合在一起使用,信号量用来同步对共享内存的访问。
调度
进程行为
几乎所有进程的(磁盘)I/O请求或计算都是交替突发的。
CPU不停顿地运行一段时间,然后发出一个系统调用以便读写文件。
在完成系统调用之后,CPU又开始计算,直到它需要读取更多的数据或写更多的数据为止。
- CPU密集型
-
I/O密集型
何时调度
- 抢占式:给每个进程分配一个时间片,用完换下一个进程
- 非抢占式:进程运行知道阻塞才换下一个进程
- 在创建一个新进程后,需要决定是运行父进程还是运行子进程。
- 在一个进程退出时必须做出调度决策。
- 当一个进程阻塞在I/O和信号量上或者由于其他原因阻塞时,必须选择另一个进程运行。
- 在一个I/O中断发生时,必须做出调度决策。
调度的目标
调度算法
-
批处理
-
先来先服务(非抢占式)
用一个单链表队列记录所有就绪进程,从尾部加入就绪进程,从首部执行进程。
缺点:对I/O密集型进程不友好,每次阻塞都要排到队尾,执行完成时间相对长。
-
最短作业优先(非抢占式)
已知进入就绪队列的进程执行时间
对进程排序,使进程的平均周转时间(即从进程进入队列到进程完成的时间)最小。
-
<a> t = (4A + 3B + 2C + D)
<b> t = (4B + 3C + 2D + A)
所以时间最长的A最末尾。
-
最短剩余时间优先(抢占式)
最短作业优先的抢占式版本
每次选择剩余运行时间最短的进程运行
-
-
交互式
-
轮转调度
维护一个就绪进程队列,每个进程分配固定的时间片长度,用完就回到队尾。
-
时间片长度过短,进程调度消耗太大;过长,则平均周转时间过长。通常设为20ms-50ms。
-
优先级调度
-
优先级高的先运行
多级队列
最短进程优先
保证调度
彩票调度
公平分享调度
-
-
-
实时
硬实时(hard real time)调度:调度机制确保一个关键任务能在指定时间前完成
软实时(soft real time)调度:调度机制尽量给予关键任务最高优先级,尽量在指定时间前完成