进程与线程
在多道程序环境下,允许多个程序并发执行,此时它们失去封闭性,并具有间断性及不可再现性的特征。为此引入进程的概念,以更好地描述和控制程序的并发执行,实现操作系统的并发性和共享性。
2.1.1、进程的概念
PCB是进程存在的唯一标志
为保证并发执行的程序能独立地运行,必须为之配置一个专门的数据结构,称为进程控制块(PCB)。
系统通过PCB来描述进程的情况和状态,从而控制和管理进程。
程序段、数据段和PCB三部分构成了进程映像(进程实体)。
进程映像是静态的,而进程则是动态的。
传统操作系统中的进程定义:进程是进程实体的运行过程,是系统进行资源分配和调度的一个独立单位。此处的资源是指处理机、存储器和其他设备服务于某进程的“时间”。这就决定了进程一定是一个动态的、过程性的概念。
2.1.2、进程的特征
- 动态性:动态性是进程最基本的特征。
- 并发性:并发性是进程的重要特征,也是操作系统的重要特征。
- 独立性:进程实体是一个能独立运行、独立获得资源和独立接受调度的基本单位。
- 异步性:由于进程的相互制约,使得进程具有间接性。异步性会导致执行结果的不可再现性。
- 结构性:进程实体由程序段、数据段和PCB三部分构成。
2.1.3、进程的状态转换
在外存进入内存的同时,由程序转变成进程。
进程一共有五种状态,分别是:创建态、就绪态、运行态、阻塞态、终止态。
就绪态与阻塞态的区分
就绪态:缺少处理机,等待获取处理机。
阻塞态:资源抢夺、进程合作而发生等待,等待获取资源。
2.1.4、进程控制
进程控制主要是对系统中的所有进程实施有效的管理,它具有创建新进程、撤销已有进程、实现进程状态转换等功能。
1、进程的创建
在操作系统中,终端用户登陆系统、作业调度、系统提供服务、用户程序的应用请求都会引起进程的创建。
- 为新进程分配一个唯一的进程标识号,并申请一个空白的PCB(PCB是有限的)。若PCB申请失败则创建失败。
- 为进程分配资源,为新进程的程序和数据,以及用户栈分配必要的内存空间(在PCB中体现)。这里资源分配不足(比如内存空间),并不是创建失败,而是处于“等待状态”,或成为“阻塞状态”,等待的是内存这个资源。
- 初始化PCB,主要包括初始化标志信息、初始化处理机状态信息和初始化处理机控制信息,以及设置进程的优先级等。
- 如果进程就绪队列能够接纳新进程,就将新进程插入到就绪队列中,等待被调度运行。
2、进程的终止
引起进程终止的事件主要有:正常结束;异常结束(进程运行时发生了某种异常事件,使程序无法继续运行,如存储越界、保护错、非法指令、特权指令错、I/O故障等);外界干预(进程应外界的请求而终止运行,如操作员干预、父进程请求和父进程终止)。
- 根据被终止进程的标识符,检索PCB,从中读出该进程的状态。
- 若被终止进程处于执行状态,立即终止该进程的执行,将处理机资源分配给其他进程。
- 若该进程还有子进程,则应将其所有子进程终止。
- 将该进程所拥有的全部资源,或归还给其父进程或归还给操作系统。
- 将该PCB从所在队列(链表)中删除。
3、进程的阻塞(进程的主动行为)
只有处于运行态的进程(获得CPU),才可能将其转为阻塞状态。
- 找到将要被阻塞进程的标识号对应的PCB。
- 若该进程为运行态,则保护其现场,将其状态转为阻塞状态,停止运行。
- 把该PCB插入到相应事件的等待队列中去。
4、进程的唤醒(进程的被动行为)
- 在该时间的等待队列中找到相应进程的PCB。
- 将其从等待队列中移出,并置其状态为就绪状态。
- 把该PCB插入就绪队列中,等待调度程序调度。
进程的阻塞是由被阻塞进程自我调用实现的,而唤醒是由一个与被唤醒进程相合作或被系统进程调用实现的。
5、进程的切换
对于通常的进程,其创建、撤销以及要求由系统设备完成的I/O操作都是利用系统调用而进入内核,再由内核中相应处理程序予以完成的。进程切换同样是在内核的支持下完成的。
任何进程都是在操作系统内核的支持下运行的,是与内核紧密相关的。
- 保存处理机上下文,包括程序计数器和其他寄存器。
- 更新PCB信息。
- 把进程的PCB移入相应的队列,如就绪、在某事件阻塞等其他队列。
- 选择另一个进程执行,并更新其PCB。
- 更新内存管理的数据结构。
- 恢复处理机上下文。
一般来说,先有资源的调度,然后才有进程的切换。
4、关于进程的唤醒
唤醒一个进程有两种方法:一种是由系统进程唤醒。另一种是由事件发生进程唤醒。
当由系统进程唤醒等待进程时,系统进程统一控制事件的发生并将“事件发生”这一消息通知等待进程。从而使得该进程因等待事件已发生而进入就绪队列。
等待进程也可由事件发生进唤醒。由事件发生进程唤醒时,事件发生进程和被唤醒进程之间是合作关系。因此,唤醒原语既可被系统进程调用,也可被事件发生进程调用。
2.1.5、进程的组织
进程是一个独立的运行单位,也是操作系统进行资源分配和调度的基本单位。
1、进程控制块(PCB)
PCB是进程实体的一部分,是进程存在的唯一标志。操作系统利用PCB表来管理和控制进程。在一个系统中,为了方便进程的调度和管理,需要将进程的PCB用适当的方法组织起来。常用的组织方法有链接方式和索引方式两种。
链接方式将同一状态的PCB链接成一个队列,不同状态对应不同的队列,也可以把处于阻塞状态的进程的PCB,根据其阻塞原因的不同,排成多个阻塞队列。
索引方式是将同一状态的进程组织在一个索引表中,索引表的表项指向相应的PCB,不同状态对应不同的索引表,如就绪索引表和阻塞索引表等。
2.1.6、进程的通信
进程的通信是指进程之间的信息交换。PV操作是低级通信方式,高级通信方式是指以较高的效率传输大量数据的通信方式。
高级通信主要有以下三个类:
- 共享存储:通信的进程之间存在一块可直接访问的共享空间。
共享存储分为两类:
低级方式的共享是基于数据结构的共享;
高级方式则是基于存储区的共享。
- 消息传递:消息传递系统中,进程利用操作系统提供的消息传递方法(发送原语,接收原语)进行数据交换。
直接通信方式:发送进程直接把消息发送给接收进程,并将它挂在接受进程的消息缓冲队列上,接收进程从消息缓冲队列中取得消息。
间接通信方式:发送进程把消息发送到某个中间实体中,接受进程从中间实体中取得信息。这种中间实体一般称为信箱,这种通信方式又称为信箱通信方式。(例如电子邮件系统)
- 管道通信:为了协调双方的通信,管道机制必须提供以下三方面的协调能力:互斥、同步和确定对方的存在。在Linux中,管道是一种使用非常频繁的通信机制,管道通信可以克服使用文件进行通信的两个问题:
1)限制管道的大小。实际上,管道是一个固定大小的缓冲区。Linux中,该缓冲区的大小为4KB。当管道被写满时,对管道的write()调用将默认地被阻塞,等待某些数据被读取,以便腾出足够的空间供write()调用写。
2)读进程也可能比写进程快。当所有当前进程数据已被读取时,管道变空。这种情况发生时,一个随后的read()调用将默认地被阻塞,等待某些数据被写入,这解决了read()调用返回文件结束的问题。
管道只能采取半双工通信,即某一时刻只能单向传输。要实现父子进程双方互动通信,需要定义两个管道。
进程与作业的关系
- 作业是用户向计算机提交任务的实体,有可能全部位于外存,而进程则是完成用户任务的执行实体,总会有一部分位于内存。
- 一个作业可由多个进程组成且至少包含一个进程,反之不可。
- 作业的概念只存在于批处理系统中。
2.2.1、线程的概念
引入线程,则是为了减小程序在并发执行时所付出的时空开销。提高操作系统的并发性能。
- 线程最直接的理解就是“轻量级进程”,它是一个CPU执行单元,也是程序执行流的最小单元,由程序ID、程序计数器、寄存器集合和堆栈组成。
- 线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其他线程共享进程所拥有的全部资源。
- 由于线程之间的相互制约,致使线程在运行中呈现出间断性,线程也有就绪、阻塞和运行三种基本状态。
进程只作为除CPU以外系统资源的分配单元,线程则作为处理机的分配单元。由于一个进程有多个线程,如果线程的切换发生在同一个进程内部,则只需要很少的时空开销。
2.2.2、线程与进程的比较
1、调度。拥有资源和独立调度的基本单位都是进程。在引入线程的操作系统中,线程是独立调度的基本单位,进程是拥有资源的基本单位。
在同一进程中,线程的切换不会引起进程切换。在不同进程中进行线程的切换,如从一个进程内的线程切换到另一个进程中的线程时,会引起进程切换。
2)拥有资源。进程是拥有资源的基本单位,而线程不拥有系统资源。
3)并发性。在引入线程的操作系统中,不仅进程之间可以并发执行,而且多个线程之间也可以并发执行,从而使操作系统具有更好的并发性,提高了系统的吞吐量。
3)系统开销。创建或撤销进程的时候,系统付出的开销远大于创建或撤销进程的开销。线程之间的同步和通信非常容易实现,甚至无需操作系统的干预。
5)地址空间和其他资源(如打开的文件):进程的地址空间之间相互独立,同一进程的各线程间共享进程的资源,某进程内的线程对于其他进程不可见。
6)通信方面。进程间通信(IPC)需要进程同步和互斥手段的辅助,以保证数据的一致性,而线程之间可以直接读/写进程数据段(如全局变量)来进行通信。
2.2.3、线程的实现方式
线程的实现可以分为两类:用户级线程(User-Level Thread,ULT)和内核级线程(Kernel-Level Thread,KLT)。内核级线程又称为内核支持的线程。
- 在用户级线程中,有关线程管理的所有工作都由应用程序完成,内核意识不到线程的存在,应用程序可以通过使用线程库设计成多线程程序。
- 在内核级线程中,线程管理的所有工作由其内核完成,应用程序没有进行线程管理的代码,只有一个到内核级线程的编程接口。内核为进程及其内部的每个线程维护上下文信息,调度也是在内核基于线程架构的基础上完成。
在一些系统上,使用组合方式的多线程实现。线程创建完全在用户空间中完成,线程的调度和同步也在应用程序中进行。一个应用程序中的多个用户级线程被映射到一些(小于或等于用户级线程的数目)内核级线程上。
2.2.4、多线程模型
1)多对一模型。将多个用户级线程映射到一个内核级线程,线程管理在用户空间完成,此模式中,用户级线程对操作系统不可见(即透明)。
优点:线程管理是在用户空间进行的,因而效率比较高。
缺点:当一个线程在使用内核服务时被阻塞,那么整个进程都会被阻塞;多个线程不能并行地运行在多处理机上。
2)一对一模型。将每个用户级线程映射到一个内核级线程。
优点:当一个线程被阻塞后,允许另一个线程继续执行,所以并发能力较强。
缺点:每创建一个用户级线程都需要创建一个内核级线程与之对应,这样创建线程的开销比较大,会影响到应用程序的性能。
3)多对多模型。将n个用户级线程映射到m个内核级线程上,要求m小于等于n。
特点:克服了多对一模型的并发度不高的缺点,又克服了一对一模型的一个用户进程占用太多内核级线程,开销太大的缺点。又拥有多对一模型和一对一模型各自的优点。