操作系统四大特质:并发,共享,虚拟,异步
都是基于进程而产生的,并从进程的角度对操作系统进行研究。在操作系统中,进程是一个极其重要的概念。

<>进程的描述

<>进程的定义和特征

<>进程的定义

在计算机中按ctrl + shift + esc,打开任务管理器,可以看到后台有很多进程

在多道程序环境下,程序的执行属于并发执行。
并发执行的特点:

* 间断性
* 失去封闭性
* 不可再现性
这决定了通常的程序是不能参与并发执行的。
为了使程序能并发执行,并且可以对并发执行的程序加以描述和控制,由此引入了进程的概念。
从不同的角度可以有不同的定义,比较典型的定义:

* 进程是程序的一次执行
* 进程是一个程序及其数据在处理及上顺序执行时所发生的活动
* 进程时具有独立功能的程序在一个数据集合上运行的过程,它是系统进行资源分配和调度的一个独立单位
一个比较好的例子:

<>进程的特征

*
结构特征

*
动态性

* 进程的实质是进程实体的执行过程
* 进程由创建而产生,由调度而执行,由撤销而消亡
*
并发性

* 多个进程实体同存于内存中,且能在一段时间内同时运行
* 程序没有PCB是不能参与并发执行的
*
独立性

* 传统OS中
独立性是指进程实体是一个能独立运行,独立获得资源和独立接受调度的基本单位。
* 凡是未建立PCB的程序都不能作为一个独立的单位参与运行
*
异步性

* 进程是按照异步方式运行的
即按各自独立的,不可预知的速度向前推进。这是由于此因,导致了传统意义的程序若参与并发执行,会产生结果的不可再现性。
* 为使进程在并发运行时虽具有一不行,但仍能保证进程并发执行的结果时可再现的,在OS中引进了进程的概念,并且配置了相应的进程同步机制。
*
制约性

* 因访问共享数据/资源或进程同步而产生制约
<>进程和程序的关系

联系:

* 程序是产生进程的基础
* 程序的每次运行构成不同的进程
* 进程是程序功能的体现
* 通过多次执行,一个程序可以对应多个进程
* 通过调用关系,一个进程可以包括多个程序
区别:

* 进程是一个动态概念,程序是一个静态概念
* 进程具有并发特征,程序没有
* 进程是竞争资源的基本单位
* 进程是程序的执行,进程有核心态/用户态
* 进程是暂时的,程序是永久的(如果不改变)
<>进程控制块PCB

<>基本概念

在学习数据结构的时候,有一个很经典的公式:

                                               程序 = 算法 + 数据结构

描述进程的数据结构: 进程控制块PCB

为了使参与并发执行的每个程序(含数据)都能独立运行,在操作系统中必须为之配置一个专门的数据结构,称为进程控制块(Process Control Block).
PCB: 操作系统管理控制进程运行所用的信息集合。

系统利用PCB来描述进程的基本情况和活动过程,进而控制和管理进程

PCB是进程存在的唯一标志

由程序段,相关的数据段,PCB 三部分构成进程实体(进程映像)

一般情况下,进程实体简称为进程。
创建进程实质上是创建进程实体中的PCB,
撤销进程实质上是撤销进程实体中的PCB

进程和程序是两个不同的概念,进程具有程序所不具备的PCB,

<>PCB 中的信息

(一)进程标识信息
进程标识符

* 外部标识符
* 内部标识符
(二)处理机状态信息保存区

*
通用寄存器
又称用户可视寄存器,是用户程序可以访问的
用于暂存信息,在大多数处理机中,有8~32个通用寄存器

*
指令计数器
存放了要访问的下一条指令的地址

*
程序状态字PSW
其中含有状态信息,如条形码,执行方式,中断屏蔽标志

*
用户栈指针
每一个用户进程都有一个或若干个与之相关的系统栈,用于存放过程和系统调用及调用地址
栈指针指向该栈的栈顶
过程调用/系统调用/中断处理 和返回时需要用到它

(三)进程调度信息

*
进程状态
指明进程的当前状态,作为进程调度和对换时的依据

*
进程优先级
是用于描述进程使用处理机的有限级别的一个整数,优先级高的进程应优先获得处理机

*
进程调度所需的其它信息
与采用的进程调度算法有关,如进程已等待的CPU的时间总和,进程已执行的时间综合

*
事件
是指进程由执行状态转变为阻塞状态所等待发生的事件,即阻塞原因

(四)进程控制信息

*
程序和数据的地址
当调度到该进程时,可以从PCB中找到其程序和数据

*
进程同步和通信机制
实现进程同步和进程通信时必需的机制
如消息队列指针,信号量等

*
资源清单
列出了进程在运行期间除CPU外所需的全部资源
另外还有一张已分配到该进程的资源的清单

*
链接指针
给出了本进程(PCB) 所在队列中的下一个进程的PCB的首地址

<>PCB的组织方式

还是刚开始的那张图,可以看到有一百多个进程,通常在一个系统中会有数十个,数百个甚至上千个进程,那么就会有对应的PCB
如果这些PCB没有加以有效的管理,那么系统就全都乱套了。

如何用适当的方式将这些PCB 组织起来呢,既然PCB是一个数据结构,那么肯定离不开数据结构中的组织方式,常用的组织方式有三种

<>线性方式(线性表)

所有的PCB都在一张线性表中,该表的首址存放在内存的一个专用区域中。

* 优点:方式简单,开销小
* 缺点:每次查找都要扫描整张表,适合进程数目不多的系统

<>链接方式(链表)

同一状态的进程其PCB 成一链表,多个状态对用多个不同的链表

<>索引方式

<>进程的基本状态及转换

<>进程的三种基本状态

* 就绪状态
* 执行状态
* 阻塞状态
<>就绪状态

* 进程已经分配了除处理机(CPU)外所有的必要资源,只要再获得处理机(CPU)就可以执行的状态
* 这样的进程可能有多个,通常按照一定的策略(如优先级策略)排成一个队列,称就绪队列
<>执行状态

* 进程已经获得CPU,其程序正在运行
* 单处理机系统中只有一个进程处于执行状态,
* 多处理机系统则有多个处于执行状态
<>阻塞状态

=自闭状态(开个玩笑)

* 正在执行的进程由于发生某事件而暂时无法继续执行的状态,即进程的执行受到阻塞
* 此时引起进程调度,OS把处理机分配给另一个就绪进程,让受阻进程处于暂停状态,将这种暂停状态称为阻塞状态,也称等待状态或封锁状态。
* 通常系统将处于阻塞状态的进程排成一个或多个队列,称为阻塞队列。
<>三种基本状态之间的转换

在下面这张图中,阻塞状态只能执行状态转换而成

<>创建状态和终止状态

为增强进程控制块(PCB) 对数据及操作的完整性要求以及增强管理的灵活性,通常在操作系统中又为进程引入了两种常见状态:
创建状态,终止状态

<>创建状态

进程是由创建而产生。
创建进程的步骤:

* 由进程申请一个空白PCB
* 向PCB中填写用于控制和管理进程的信息
* 为就昵称分配运行时所必须的资源
* 该进程转入就绪状态并插入就绪队列中
但是如果进程所需的资源尚不能得到满足,创建工作就无法完成,进程不能被调度运行,此时进程所处的状态被称为创建状态

引入创建状态是为了保证进程的调度必须在创建工作完成后执行,确保对进程控制块(PCB) 操作的完整性
也增加了操作系统的灵活性,比如可以推迟新进程的提交(创建状态)

<>终止状态

终止进程的步骤:

* 等待操作系统进行善后处理
* 将其PCB 清零,并将PCB 空间返回系统
进入终止状态有下面几种可能:

* 一个进程到达了自然结束点,
* 出现了无法克服的错误,
* 被操作系统所终结,
* 被其它有终止权的进程所终结
但是终止状态并不代表进程被销毁。
进入终止状态的进程以后不能再执行,但是再操作系统中仍然保留记录,供其它进程收集,一旦其它进程完成了对其信息的提取,操作系统将删除该进程。

<>挂起状态

进程没有占用内存空间,称为进程挂起

挂起就是把一个进程从内存转到外存。

挂起有以下几种情况:

* 阻塞到阻塞挂起
没有进程处于就绪状态或就绪进程要求更多资源时,会进行这种转换,以提交新进程或运行就绪进程
* 就绪到就绪挂起
当有高优先级阻塞(系统认为很快就会就绪的)进程和低优先级就绪进程时,系统会选择挂起低优先级就绪进程
* 运行到就绪挂起
对抢先式分时系统,当有高优先级阻塞挂起进程因事件出现而进入就绪挂起时,系统可能会把运行进车给转到就绪挂起状态
操作系统中引入了一个对进程的重要操作 ——挂起操作。
当挂起操作应用于某个进程时,该进程将被挂起,意味着进程将处于静止状态。
如果进程正在执行,它将暂停执行。
如果进程原本处于就绪状态,则该进程此时暂时不接受调度。
与挂起操作对应的是激活操作

进程挂起有两种状态:

* 阻塞挂起状态:进程在外存并等待某事件的出现。
* 就绪挂起状态:进程在外存,但只要进入内存,就可以运行
<>为什么引入挂起操作?

是基于系统和用户的如下需要

* 终端用户需要
* 父进程请求
* 负荷调节的需要
* 操作系统的需求
<>引入挂起操作后进程状态的转换

在引入挂起原语Suspend 和 激活原语Active 后,进程转换如下

* 活动就绪 → 静止就绪
就绪状态有两种。当进程处于未被挂起的就绪状态时,称此为活动就绪状态,表示为Readya
使用Suspend将该进程挂起后,进程变为静止就绪状态,表示为Readys。
处于Readya的状态可以接受调度,处于Readys的状态不再被低啊都执行。
* 活动阻塞Blockeda→静止阻塞Blockeds
未被挂起的阻塞状态称它为活动阻塞,,
当静止阻塞的进程所期待的事件出现后,便从静止阻塞变为静止就绪Readys状态
* 静止就绪→活动就绪
Readys状态的进程用激活原语Active激活后,变成Readya状态
* 静止阻塞→活动阻塞
Bolckeds状态的进程用激活原语Active激活后,变成Blockeda状态
具有挂起状态的进程状态图

具有创建,终止,挂起状态的进程状态图

<>进程控制

顾名思义,进程控制就是控制进程,对系统中的所有进程实施有效的管理。
创建进程,撤销进程,进程转换等都属于进程控制。

操作系统中,控制进程的程序段称为原语,
原语的特点是执行期间不允许中断,它是一个不可分割的基本单位。

任何进程都是在操作系统内核的支持下运行的,是与内核紧密相关的。

<>进程的创建

允许一个进程创建另一个进程。
创建者称为父进程,被创建的进程称为子进程。
子进程可以继承父进程拥有的资源。子进程被撤销时,应将其从父进程那里获得的资源归还给父进程。
在撤销父进程时,必须同时撤销其所有的子进程。
引起进程创建的原因。

* 终端用户登录系统
* 作业调度
* 系统提供服务
* 用户程序的应用程序请求
创建新进程的过程如下:

* 为新进程分配一个唯一的进程标识符(有的地方叫进程标识号,是一样的)PID,并申请一个空白的PCB(PCB是有限的),若PCB申请失败,则创建失败
* 为进程分配资源
为新进程的程序和数据,以及用户栈分配必要的内存空间(在PCB中体现)
分配资源的时候若资源不足,处于等待状态或阻塞状态(此处不是很清楚,书上和网上说的有点矛盾)
* 初始化PCB
主要包括初始化标志信息,初始化处理机状态和初始化处理机控制信息,以及设置进程的优先级等
* 插入就绪队列
如果进程就绪队列能够接纳新进程,就将新进程插入就绪队列,等待被调度运行
<>进程的终止

引起进程终止的原因:

* 正常结束
* 异常结束
* 外界干预
终止进程的过程( 撤销原语)

* 根据被终止进程的标识符,检索PCB,从中读出该进程的状态
* 若被终止进程处于执行状态,立即终止该进程的执行,将处理机资源分配给其它进程
* 若该进程还有子进程,则应将其所有子进程终止
* 将该进程所拥有的全部资源,归还给其父进程或操作系统
* 将该PCB从所在队列(链表)中删除
<>进程的阻塞和唤醒

为什么进程的阻塞和唤醒要放在一起呢?
因为Block原语和Wakeup原语是作用相反的原语,必须成对使用

(执行中的)进程阻塞的原因:
进程期待的事件未发生,如:

* 请求系统资源失败
* 等待某种操作完成
* 新数据尚未到达
* 无新工作可做
此时系统自动执行阻塞原语Block,使自己由运行状态变为阻塞状态
进程的阻塞是进程自身的一种主动行为,所以只有处于运行态的进程(获得CPU) 才可以将其转换未阻塞状态。
阻塞进程的过程(阻塞原语)

* 找到待被阻塞进程的标识号对应的PCB
* 若进程处于运行状态,保护现场,将其状态转换为阻塞状态,停止运行。
* 把PCB插入到相应事件的等待队列中。
当被阻塞进程所期待的事情发生后,调用唤醒原语(Wakeup),将等待该事件的进程唤醒。

唤醒进程的过程(唤醒原语)

* 在该事件的等待队列中找到相应进程的PCB
* 将PCB从等待队列中移出,并置其状态为就绪状态
* 把该PCB插入就绪队列中,等待调度程序调度
进程的唤醒是被动的行为,只能通过别的进程或操作系统唤醒

<>进程切换

进程切换是指处理机从一个进程的运行转到另一个进程上运行,这个过程中,进程的运行环境发生了实质性的变化。
进程切换的过程:

* 保存处理机上下文,包括程序计数器和其它寄存器
* 更行PCB信息
* 把进程的PCB移入相应的队列,如就绪,在某事件阻塞等队列
* 选择另一个进程,并更新其PCB
* 更新内存管理的数据结构
* 恢复处理机上下文
注意:进程切换与处理机模式切换不同,模式切换时,处理机逻辑上可能还在同一进程中运行。
如果进程因中断或异常进入到核心态运行,执行完后又回到用户态刚被中断的程序运行,操作系统只需要恢复进入内核时所保存的CPU现场,无需改变当前的进程环境信息。
但若切换进程,当前运行进程改变了,当前进程的环境信息也需要改变。、

<>进程的通信

进程通信是指进程间的信息交换。

进程之间是相互独立的
PV操作(就是进程的互斥和同步)是低级通信方式。高级通信方式是指以较高的额效率传输大量数据的通信方式。
主要有以下三个类:

<>共享存储

通信的进程之间存在一块可以直接访问的共享空间,通过对这片共享空间进行读/写操作实现进程之间的信息交换。
在对共享空间进行读/写操作时,需要使用同步互斥工具(如PV操作)对共享空间的读/写进行控制。
共享存储又分为两种:

*
低级方式的共享是基于数据结构的共享

*
高级方式的共享是基于存储区的共享

操作系统只负责为通信进程提供可共享使用的存储空间和同步互斥工具,
数据交换则由用户自己安排 读/写指令 完成

用户进程空间一般是独立的,进程运行期间一般不能访问其它进程的空间,要想让两个用户进程共享空间必须通过特殊的系统调用实现,进程内的线程是自然共享进程空间的

<>消息传递

消息交换的单位是消息或报文(计算机网络中将消息称为 报文)

消息传递系统中,进程间的数据交换是以格式化的消息(Message) 为单位的。
若进程之间不存可以直接访问的共享空间,必须利用操作系统提供的消息传递方法实现进程通信,进程通过系统提供的发送消息和接受消息两个原语进行数据交换

<>直接通信方式

发送进程直接发送消息到接受进程,并将消息挂在接收进程的的消息缓冲队列上,接收进程从消息缓冲队列中取得消息

系统提供两条通信原语

* Send(Receiver,message)
* Receive(Sender,message)
<>间接通信方式(信箱通信方式)

发送进程把消息发送给信箱,接受进程从信箱中取得消息,这种通信方式又称为信箱通信方式。
信箱通信方式广泛应用于计算机网络中,相应的通信系统称为电子邮件系统。
消息在信箱中可以安全的保存,只允许核准的目标用户随时读取,可实现非实时通信

<>信箱

<>信箱的创建与撤销

* 进程通过信箱创建原语来建立一个新信箱
创建者进程应给出信箱名字,信箱属性(公用,私用,共享)
对于共享信箱,还应给出共享者的名字
* 用信箱撤销原语来撤销
<>消息的发送与接受

* Send(mailbox,message) : 将一个消息发送到指定邮箱
* Receive(mailbox,message): 从指定信箱中接受一个消息
<>信箱的分类

*
私用信箱

* 用户进程建立,作为该进程的一部分
* 拥有者有权读消息,其它用户只能发送
* 采用单向通信链路
* 进程结束时信箱也消失
*
公用信箱

* 由OS 创建
* 提供给系统中所有的核准进程使用
* 进程既可以发送也可以取出
* 采用双向通信链路的信箱来实现
* 系统运行期间始终存在
*
共享信箱

* 由某进程创建,创建时提供共享进程(用户)的名字
* 信箱的拥有者和共享者,都有权从信箱中取走发送给自己的消息
<>信箱通信时发送进程和接受进程的关系

* 一对一关系
建立一条专用的通信链路
* 多对一关系
服务进程与多个用户进程之间实行交互,又称客户/服务器交互
* 一对多关系
一个发送进程与多个接受进程进行交互,使发送进程可用广播形式向接收者发送消息
* 多对多关系
建立一个公用信箱,多个进程投递并取走自己的消息
<>管道通信

1) 管道通信方式建立在文件系统的基础上,利用共享文件来连接两个互相通信的进程,此共享文件称为管道(Pipe)
2) 管道是指用于连接一个读进程和一个写进程,以实现他们之间通信的共享文件

<>管道通信必要的协调能力

*
互斥
当一个进程正在对管道进行读/写操作时,另一个进程必须等待

*
同步
当写(输入)进程把一定的数据(如4K)写入管道后,便去睡眠等待,直到读(输出)进程取走数据后再把它唤醒。
当读进程发现管道空时,也应睡眠等待,直到写进程将消息写入管道后,才将它唤醒

*
判断对方是否存在
只有在确定对方存在时才能进行通信

从管道读数据是一次性操作,数据一旦被读取,它就从管道中被抛弃,释放空间以便写更多的数据。
管道只能采用半双工通信,即某一时刻只能单向传输。
要实现父子进程双方互相通信,需要定义两个管道。

<>线程

回顾一下为什么要引入进程:
引入进程的目的,是为了更好地使多道程序并发执行,以提高资源利用率和系统吞吐量,增加并发程度。
进程的两个属性:

* 进程是一个可拥有资源的独立单位
* 进程同时又是一个可独立调度和分派的基本单位。
既然进程拥有资源,还是独立调度和分派的基本单位,已经能够使程序并发执行了。为什么还要引入线程呢?

正如古话所说:杀鸡焉用牛刀
,用进程处理一些小的比较复杂的事件,用进程处理就会显得很笨重,付出了较大的时空开销,这就限制了系统中所设置的进程的数目,而且进程切换也不宜过于频繁,限制了并发程度的进一步提高。所以把传统进程称为中兴进程。
而线程又称为轻型进程或进程元。

<>线程与进程比较

*
调度的基本单位
在传统OS中,进程是作为独立调度和分派的基本单位,因而进程是能独立运行的基本单位。在每次被调度时,都需要进行上下文切换,开销很大。
引入线程的OS中,把线程作为调度和分派的基本单位,而进程是拥有资源的基本单位
同一进程中,线程切换不会引起进程切换
但从一个进程中的线程切换到另一个进程中的线程时,必然会引起进程的切换

*
并发性
多个线程(同一进程或不同进程)之间可以并发执行

*
拥有资源

进程是拥有资源的基本单位,线程不拥有系统资源,如果拥有系统资源,那么线程和进程就是一样的了。但是线程也又一点必不可少的,能保证独立运行的基本资源,线程可以访问其隶属进程的系统资源。

*
系统开销
线程切换时,只需要保存和设置少量寄存器内容,开销很小。
而且由于统一进程的所有都具有相同的地址空间(共享进程的地址空间),线程之间的同步与通信非常容易实现,甚至无需操作系统干预

*
地址空间和其它资源
进程的地址空间之间互相独立,同一进程的各线程间共享进程的资源,某进程内的线程对于其它进程不可见

*
通信方面
进程间通信(IPC)需要进程同步和互斥手段的辅助,以保证数据的一致性,而线程间可以直接读/写进程数据段(如全局变量)来进行通信。

<>线程的属性

* 线程是一个轻型实体,它不拥有系统资源,但每个线程都应有一个唯一的标识符和一个线程控制块(TCB),TCB记录了线程执行的寄存器和栈等现场状态
* 不同的线程可以执行相同的程序,即同一个服务程序被不同的用户调用时,操作系统为他们创建不同的线程
* 同一进程中的各个线程共享该进程所拥有的资源
*
线程是处理机的独立调度单位,多个现车给是可以并发执行的,在单CPU的计算机系统中,各线程可以交替的占用CPU,多CPU的计算机系统中,各线程可同时占用不同的CPU。
* 一个线程被创建后便开始了它的生命周期,直至终止,线程在生命周期中会经历阻塞态,就绪态,运行态等各种状态变化。
<>线程的实现方式

线程的实现方式可以分为两类:

* 内核支持线程(Kernel Supported Threads)
* 用户级线程UTL(User Level Threads)
<>内核支持线程KST

OS中的所有进程,无论是系统进程还是用户进程,都是在操作系统内核的支持下运行的,是与内核紧密相关的。而内核支持线程KST同样是在内核的支持下运行的,他们的创建,阻塞,撤销,切换都是在内核空间中实现的。
内核空间也为每一个内核线程设置了一个线程控制块TCB,内核根据该控制块而感知某线程的存在,并对其加以控制。
KST的四个优点:

* 多处理器系统中,内核能同时调度同一进程中的多个线程并行执行
* 如果进程中的一个线程被阻塞,内核可以调度该进程中的其它线程占有处理器,也可以运行其它进程中的线程。
* 内核支持线程具有很小的数据结构和堆栈,线程的切换比较快,切换开销小
* 内核本身也可以采用多线程技术,可以提高系统的执行速度和效率
KST的缺点:
用户进程的线程在用户态运行
用户线程切换时,需要从用户态转到核心态进行,模式切换的开销较大。

<>用户级线程ULT

用户级线程是在用户空间中实现的,对线程的创建,撤销,同步,通信等功能,都无需内核的支持,即用户级线程是与内核无关的。这些线程的任务控制块都是设置在用户空间,线程所执行的操作也无需内核支持,因而内核完全不知道用户级线程的存在。

注意!!!
设置了用户级线程的系统,其调度仍是以进程为单位进行的
设置了内核支持线程的系统,其调度便是以线程为单位进行的。

ULT的优点:

* 线程切换不需要转换到内核空间
* 调度算法可以是进程专用的
* 用户级线程的实现与OS平台无关
ULT的缺点:

* 系统调用的阻塞问题

在基于进程机制的OS中,大多数系统调用将会使进程阻塞,因此,当线程执行一个系统调用时,不仅该进程被阻塞,而且进程内的所有线程会被阻塞。而在内核支持线程方式中,进程中的其它线程仍然可以运行。
*
在单纯的用户级线程实现方式中,多线程应用不能利用多处理机进行多重处理的优点,内核每次分配给一个进程仅有一个CPU,因此,进程中仅有一个线程能执行,在该线程放弃CPU之前,其它线程只能等待。
<>多线程模型

有些OS同时支持KST和ULT,提供了组合方式ULT/KST 线程,由此产生了不同的多线程模型,即实现了用户级线程和内核级线程的连接方式。

*
多对一模型
将用户线程映射到一个内核控制线程

优点:

* 线程管理开销小
* 线程管理效率高
缺点:

* 如果一个线程在访问内核时发生阻塞,整个进程都会被阻塞
* 任意时刻,只有一个线程能访问内核,多个线程不能同时在多个处理机上运行。
*
一对一模型
每一个用户线程映射到一个内核支持线程

优点:

* 当一个线程阻塞时,允许调度另一个线程运行,提供了比多对一模型更好的并发功能
* 多处理机系统中,允许多个线程并行地运行在多处理机系统中
缺点:

* 每创建一个用户级线程都需要创建一个内核级线程与其对应,这样创建线程的开销较大,会影响到应用程序的性能。

*
多对多模型
将n个用户级线程映射到m个内核级线程中,要求 m<= n(内核级线程<用户级线程);

特点:结合了上述两种模型的优点,可以像一对一模型那样,时一个进程的多个线程并行地运行在多处理机系统上,也可以像多对一模型那样,减少线程的管理开销和提高效率。

技术
下载桌面版
GitHub
Gitee
SourceForge
百度网盘(提取码:draw)
云服务器优惠
华为云优惠券
腾讯云优惠券
阿里云优惠券
Vultr优惠券
站点信息
问题反馈
邮箱:[email protected]
吐槽一下
QQ群:766591547
关注微信