OS操作系统系列文章目录
【OS操作系统】Operating System 第一章:操作系统的概述
【OS操作系统】Operating System 第二章:启动、中断、异常和系统调用
【OS操作系统】Operating System 第三章:连续内存分配
【OS操作系统】Operating System 第四章:非连续内容分配
【OS操作系统】Operating System 第五章:虚存技术
【OS操作系统】Operating System 第六章:页面置换算法
【OS操作系统】Operating System 第七章:进程与线程
【OS操作系统】Operating System 第八章:处理机调度
【OS操作系统】Operating System 第九章:同步互斥问题
【OS操作系统】Operating System 第十章:信号量与管程
【OS操作系统】Operating System 第十一章:死锁与进程通信
【OS操作系统】Operating System 第十二章:文件系统
目录
第七章:进程与线程
进程(process)的描述
- 进程的定义:
一个具有一定独立功能的程序在一个数据集合上的一次动态执行过程;
- 进程的组成:
- 程序的代码;
- 程序处理的数据;
- 程序计数器中的值,指示下一条将运行的指令;
- 一组通用的寄存器的当前值、堆、栈;
- 一组系统资源(如打开的文件);
- 进程与程序的联系:
- 程序是产生进程的基础;
- 程序的每次运行构成不同的进程;
- 进程是程序功能的体现;
- 通过多次执行,一个程序可以对应多个进程,通过调用关系,一个进程可包括多个程序;
- 进程与程序的区别:
- 进程是动态的,程序是静态的:
程序是有序代码的集合,进程是程序的执行,进程有核心态、用户态; - 进程是暂时的,程序是永久的:
进程是一个状态变化的过程,程序可以长久保存; - 进程和程序的组成不同:
进程的组成包括程序,数据和进程控制块(进程状态信息);
- 进程是动态的,程序是静态的:
- 实例:
- 进程的特点
- 动态性:
可动态地创建、结束进程; - 并发性:
进程可以被独立调度并占用处理机运行;(并发:一段时间;并行:某一时刻); - 独立性:
不同进程的工作不会相互影响(页表是保障措施之一); - 制约性:
因访问共享数据、资源或进程间同步而产生制约;
- 动态性:
- 程序 = 算法 + 数据结构
- 进程控制块(PCB):
描述进程的数据结构,操作系统管理进程运行所用的信息集合; - 操作系统为每个进程都维护了一个PCB,用来保存与该进程有关的各种状态信息,PCB是进程存在的唯一标志;
- 进程控制块(PCB):
- 进程的控制结构:
- 描述进程的数据结构为进程控制块(PCB);
操作系统为每个进程都维护了一个PCB,用来保存与该进程有关的各种状态信息; - 进程的创建:为该进程生成一个PCB;
- 进程的终止:回收它的PCB;
- 进程的组织管理:通过对PCB的组织管理来实现;
- 描述进程的数据结构为进程控制块(PCB);
- PCB有三大信息:
- 进程标志信息:
如本进程的标志,本进程的产生者标志(父进程标志),用户标志; - 处理机状态信息保存区:
保存进程的运行现场信息;- 用户可见寄存器:用户程序可以使用的数据、地址等寄存器;
- 控制和状态寄存器:如程序计数器(PC)、程序状态字(PSM);
- 栈指针:过程调用、系统调用、中断处理和返回时需要用到它;
- 进程控制信息:
- 调度和状态信息:用于操作系统调度进程并占用处理机使用;
- 进程间通信信息:为支持进程间与通信相关的各种标志、信号、信件等,这些信息都存在接收方的进程控制块;
- 存储管理信息:包含有指向本进程映像存储空间的数据结构;
- 进程所用资源:说明由进程打开,使用的系统资源,如打开的文件等;
- 有关数据结构的链接信息:进程可以连接到一个进程队列中,或连接到相关的其它进程的PCB;
- 进程标志信息:
- 进程的组织方式
- 链表:
同一状态的进程,其PCB成一链表,多个状态对应多个不同的链表;(各状态的进程形成不同的链表:就绪链表、阻塞链表) - 索引表:
同一状态的进程归入一个索引表(由索引指向PCB),多个状态对应多个不同的索引表(各状态的进程形成不同的索引表:就绪索引表、阻塞索引表);
- 链表:
进程的状态
进程的生命周期管理
- 进程的创建:
- 系统初始化;
- 用户请求创建一个新进程;
- 正在运行的进程执行了创建进程的系统调用;
- 进程的运行:
- 内核选择一个就绪的进程,让它占用处理机并执行;
-
进程的等待(阻塞):
进程只能自己阻塞自己,因为只有进程自身才知道何时需要某种事件的发生;- 请求并等待系统服务,无法马上完成;
- 启动某种操作,无法马上完成;
- 需要的数据没有到达;
-
进程的唤醒:
进程只能被别的进程或操作系统唤醒;- 被阻塞进程需要的资源得到了满足;
- 被阻塞进程等待的事件到达;
- 将该进程的PCB插入到就绪队列;
- 进程的结束:
- 正常退出(自愿性);
- 错误退出(自愿性);
- 致命错误(强制性);
- 被其它进程杀死(强制性):
进程的状态变化模型
- 进程在生命结束前处于且仅处于三种基本状态之一,不同系统设置的进程状态数目不同;
- 进程的三种基本状态:
- 运行状态(running):当一个进程正在处理机上运行时;
- 就绪状态(ready):一个进程获得了除处理机以外的一切所需资源,一旦得到处理机即可运行;
- 等待(阻塞)状态(blocked):一个进程正在等待某一事件而暂停运行时的状态,如等待资源、等待I/O完成;
- 进程的其它基本状态:
- 创建状态(new):一个进程正在被创建,还没被转到就绪状态之前的状态;
- 结束状态(exit):一个进程正在从系统中消失时的状态,这是因为进程结束或由于其它原因所导致的;
- 可能的状态变化:
-
N
U
L
L
→
N
e
w
NULL~\rarr~New
NULL → New:
一个新进程被产生出来执行一个程序; -
N
e
w
→
R
e
a
d
y
New~\rarr~Ready
New → Ready:
当进程被创建完成并初始化后,一切就绪准备运行时,变为就绪状态; -
R
e
a
d
y
→
R
u
n
n
i
n
g
Ready~\rarr~Running
Ready → Running:
处于就绪状态的进程被进程调度程序选中后,就分配到处理机上运行; -
R
u
n
n
i
n
g
→
E
x
i
t
Running~\rarr~Exit
Running → Exit:
当进程表示它已经完成或者因出错,当前运行进程会由操作系统作结束处理; -
R
u
n
n
i
n
g
→
R
e
a
d
y
Running~\rarr~Ready
Running → Ready:
处于运行状态的进程在其运行过程中,由于分配给它的处理机时间片用完而让出处理机; -
R
u
n
n
i
n
g
→
B
l
o
c
k
e
d
Running~\rarr~Blocked
Running → Blocked:
当进程请求某样东西且必须等待时; -
B
l
o
c
k
e
d
→
R
e
a
d
y
Blocked~\rarr~Ready
Blocked → Ready:
当进程要等待某事件到来时,它从阻塞状态转为就绪状态;
-
N
U
L
L
→
N
e
w
NULL~\rarr~New
NULL → New:
进程的挂起
- 进程挂起:
- 为了合理且充分地利用系统资源的;
- 挂起时,进程没有再占用内存空间,而是将进程映像在磁盘上;
- 两种挂起状态:
- 阻塞挂起状态(blocked-suspend):
进程在外存并等待某事件的出现; - 就绪挂起状态(ready-suspend):
进程在外存,但只要进入内存,即可运行;
- 阻塞挂起状态(blocked-suspend):
- 相关状态转换
- 内存
→
\rarr
→ 外存:
- 阻塞
→
\rarr
→ 阻塞挂起:
没有进程处于就绪状态,或就绪进程要求更多内存资源时,会进行该状态转换,以提交新进程或运行新就绪进程; - 就绪
→
\rarr
→ 就绪挂起:
当有高优先级阻塞(系统认为会很快就绪的)进程和低优先级就绪进程时,系统会选择挂起低优先级就绪进程; - 运行
→
\rarr
→ 就绪挂起:
对抢先式分时系统,当有高优先级阻塞挂起进程因事件出现而进入就绪挂起时,系统可能会把运行进程转到就绪挂起状态;
- 阻塞
→
\rarr
→ 阻塞挂起:
- 外存内部:
- 阻塞挂起
→
\rarr
→ 就绪挂起:
当有阻塞挂起因相关事件出现时,系统会把阻塞挂起进程转换为就绪挂起进程;
- 阻塞挂起
→
\rarr
→ 就绪挂起:
- 外存
→
\rarr
→ 内存(解挂/激活,activate):
- 就绪挂起
→
\rarr
→ 就绪:
没有就绪进程或挂起就绪进程优先级高于就绪进程时,会进程这类转换; - 阻塞挂起
→
\rarr
→ 阻塞:
当一个进程释放足够内存时,系统会把高优先级阻塞挂起(系统认为会很快出现所等待的事件)进程转换为阻塞进程;
- 就绪挂起
→
\rarr
→ 就绪:
- 内存
→
\rarr
→ 外存:
状态队列
- 状态队列:
- 状态队列是由操作系统来维护的一组队列,用来表示系统当中所有进程的当前状态;
- 不同的状态分别用不同的队列来表示(就绪队列、各种类型的阻塞队列等);
- 每个进程的PCB都根据它的状态加入到相应的队列当中,当一个进程的状态发生变化时,它的PCB从一个状态队列中脱离,加入到另一个状态队列中;
线程(Thread)
为什么使用线程
-
案例:编写一个MP3播放软件,其核心功能模块有3个:
- 从MP3音频文件当中读取数据;
- 对数据进行解压缩;
- 把解压缩后的音频数据播放出来;
-
单进程方案
问题:- 播放出来的声音能否连贯?
- 各个函数之间不是并发执行,影响资源的使用效率;
main() {
while (true) {
Read(); //I/O
Decompress(); //CPU
Play();
}
}
Read() {...}
Decompress() {...}
Play() {...}
- 多进程方案
问题:- 进程之间如何通信,共享数据?
- 维护进程的系统开销极大:
创建进程时,分配资源、建立PCB;
撤销进程时,回收资源、撤销PCB;
进程切换时,保存当前进程的状态信息;
//程序1
main() {
while (true) {
Read();
}
}
Read() {...}
//程序2
main() {
while (true) {
Decompress();
}
}
Decompress() {...};
//程序3
main() {
while (true) {
Play();
}
}
Play() {...}
- 因此,这里应有一种实体,它们之间可以并发地执行,且它们之间共享相同的地址空间;
- 这类实体就是线程;
线程的基本概念
- 线程的定义:
线程是进程中的一条执行流程;
进程 = 资源管理 + 线程;
从两个方面理解:
- 从资源组合的角度:
进程把一组相关的资源组合起来,构成了一个资源平台(环境),包括地址空间(代码段,数据段)、打开的文件等各种资源; - 从运行的角度:
代码在这个资源平台上的一条执行流程(线程);
- 从资源组合的角度:
- 线程的优点:
- 一个进程中可以同时存在多个线程;
- 各个线程之间可以并发地执行;
- 各个线程之间可以共享地址空间和文件等资源;
- 线程的缺点:
一个线程的崩溃,可能会导致该进程下的所有线程都崩溃;
- 不同操作系统对线程的支持:
-
线程所需的资源:
-
线程与进程的比较:
- 进程是资源分配单位,线程是CPU调度单位;
- 进程拥有一个完整的资源平台,而线程只独享必不可少的资源,如寄存器和栈;
- 线程同样具有就绪、阻塞和执行三种基本状态,同样具有状态之间的转换关系;
- 线程能减少并发执行的时间和空间开销:
- 线程的创建时间比进程短(直接利用所属进程的一些状态信息);
- 线程的终止时间比进程短(不需要考虑把这些状态信息给释放);
- 同一进程内的线程切换时间比进程短(同一进程不同线程的切换不需要切换页表);
- 由于同一进程的各线程之间共享内存和文件资源,可直接进行不通过内核的通信(直接通过内存地址读写资源);
线程的实现
- 主要有三种线程实现的方法:
- 用户线程:
在用户空间实现,例如POSIX Pthreads, Mach C-threads, Solaris threads
; - 内核线程:
在内核中实现,例如Windows, Solaris, Linux
; - 轻量级进程:
在内核中实现,支持用户线程,例如Solaris
;
- 用户线程:
- 用户线程与内核线程的对应关系:
- 多对一;
- 一对一;
- 多对多;
用户线程
- 基本概念:
在用户空间实现的线程机制,不依赖于操作系统的内核,由一组用户级的线程库来完成线程的管理,包括创建、终止、同步和调度等;
这使得操作系统只能看到进程,无法看到用户线程,因为线程的TCB在线程库中实现;
- 用户线程的优点:
- 由于用户线程的维护由相应的进程来完成(通过线程库函数),不需要操作系统内核了解用户进程的存在,可用于不支持线程技术的多进程操作系统;
- 每个进程都需要它自己私有的线程控制块(TCB)列表,用来跟踪记录它的各个线程的状态信息(PC、栈指针、寄存器),TCB由线程库函数来维护;
- 用户线程的切换也是由线程库函数来完成,无需用户态与核心态的切换,所以速度特别块;
- 允许每个进程拥有自定义的线程调度算法;
- 用户进程的缺点:
- 阻塞性系统中,如果一个线程发起系统调用而进入阻塞,则整个进程都在等待;
- 当一个线程开始运行时,除非它主动地交出CPU的使用权,否则它所在的进程当中的其它线程将无法运行;
- 由于时间片段分配给进程,所以与其它进程相比,在多线程执行时,每个线程得到的时间片较少,执行会较慢;
内核线程
- 基本概念:
内核线程是在操作系统的内核中实现的一种线程机制,由操作系统的内核完成线程的创建、终止和管理;
操作系统能够看到进程也可以看到内核线程;
- 应用:
- 在支持内核线程的操作系统中,由内核去维护进程和线程的上下文信息(PCB和TCB);
- 线程的创建、终止和切换都是通过系统调用或内核函数来实现的,由内核来完成,因此系统的开销较大;
- 在一个进程当中,如果某个内核线程发起系统调用而被阻塞,并不会影响其它内核线程的运行;
- 时间片分配给线程,多线程的进程会获得更多CPU时间;
Windows NT
和Windows 2000/XP
支持内核线程;
轻量级进程
- 它是内核支持的用户线程;
- 一个进程可以有一个或多个轻量级进程;
- 每个轻量级进程由一个单独的内核线程来支持(
Solaris/Linux
);
上下文切换
- 上下文切换的过程:
停止当前运行的进程(从运行态转变为其它状态),并且调度其它进程(从其它状态转变为运行态);- 必须在切换之前存储许多部分的进程上下文;
- 必须能够在之后恢复它们,所以进程不能显示它曾经被暂停过;
- 必须加速(因为上下文切换会非常频繁);
- 上下文切换中存储的内容:
- 寄存器(PC,SP,…),CPU状态等信息;
- 一些时候可能会比较费时,应该尽可能避免;
- 操作系统为了活跃进程,会准备进程控制块PCB,而这些PCB将会放置到合适的队列中;
- 就绪队列;
- 等待I/O队列(每个设备的队列);
- 僵尸队列;