目录
1--进程
1-1--进程的定义
进程表示一个具有一定独立功能的程序在一个数据集合上的一次动态执行过程;
1-2--进程的组成
一个进程由以下部分组成:① 程序的代码; ② 程序处理的数据;③ 程序计数器中的值,其指示下一条将运行的指令;④ 一组通用的寄存器的当前值、堆和栈;⑤ 一组系统资源;简而言之,进程记录了正在运行的一个程序的所有状态信息;
1-3--进程与程序的关系
进程与程序具有以下关系:
① 程序是产生进程的基础;
② 程序的每次运行构成不同的进程;
③ 进程是程序功能的体现;
④ 通过多次执行,一个程序可以对应多个进程;通过调用关系,一个进程可以包括多个程序;
进程与程序的区别:
① 进程是动态的,程序是静态的;
② 程序是有序代码的集合,进程是程序的执行,进程有核心态和用户态;
③ 进程是暂时的,程序是永久的;进程是一个状态变化的过程,程序可以长久保存;
④ 进程与程序的组成不同,进程的组成包括程序、数据和进程控制块(Process Control Block,即 PCB 用于描述进程的数据结构,操作系统为每个进程都维护了一个PCB,用于保存与该进程有关的各种状态信息);
1-4--进程的特点:
进程具有以下特点:
① 动态性:进程可以动态地创建和结束;
② 并发性:进程可以被独立调度并占用处理机进行运行;(并发:一段时间内多个线程同时执行;并行:一个时刻多个线程同时执行;)
③ 独立性:不同进程的工作不相互影响;
④ 制约性:进程由于访问共享数据、资源,或者进程间同步会产生相互的制约(涉及互斥、锁等问题);
1-5--进程控制结构
进程控制块:表示操作系统管理控制进程运行所用的信息结合;操作系统通过进程控制块(PCB)来描述进程的基本情况以及运行变化的过程,PCB是进程存在的唯一标志;
使用进程控制块时,创建进程会为进程生成一个PCB,终止进程会回收其PCB,对进程的组织管理是通过对PCB的组织管理实现的;
PCB包含以下三大类信息:
① 进程标识信息:本进程的标识,本进程的父进程标识、用户标识等;
② 处理机状态信息保存区:保存进程的运行现场信息;
③ 进程控制信息:例如调度和状态信息、进程间通信信息、存储管理信息、进程所用资源和有关数据结构连接信息;
PCB的组织方式:
① 链表:同一状态的进程其PCB组成一个链表,不同状态(例如就绪、阻塞等)对应不同的链表;
② 索引表:同一状态的进程归入一个 index 表,不同状态(例如就绪、阻塞等)对应不同的 index 表;
1-6--进程的生命周期
进程的生命期管理包括以下部分:
① 进程创建:系统初始化时,用户请求创建一个新进程,正在运行的进程执行了创建进程的系统调用;
② 进程运行:内核选择一个就绪的进程,让它占用处理机并运行;
③ 进程等待:在部分情况下,进程会进入等待(阻塞)的状态,例如请求并等待系统服务时,无法立刻完成,进程会进入等待状态;启动某种操作时,无法立刻完成,进程会进入等待状态;进程需要的数据没有到达时,进程会进入等待状态;进程只能自己阻塞自己;
④ 进程唤醒:进程在以下情况会从等待状态被唤醒,进入唤醒状态,例如被阻塞进程需要的资源被满足时;被阻塞进程等待的事件到达时;该进程的PCB被插入到就绪队列中;进程只能被别的进程或操作系统唤醒;
⑤ 进程结束:进程在以下四种情形下会结束,例如自愿正常退出、自愿错误退出、强制致命错误、强制被其他进程杀死;
1-7--进程状态变化模型
进程在生命结束之前将处于并仅处于以下三种基本状态:
① 运行状态(Running):一个进程正在处理机上运行;
② 就绪状态(Ready):一个进程获得了除处理机之外的一切资源,当得到处理机时即可运行;
③ 等待/阻塞状态(Blocked):一个进程正在等待某一事件而暂停运行;
1-8--进程挂起
进程处于挂起状态时,进程不占用内存空间,处于挂起状态的进程会映射到磁盘(外存)上;
挂起状态有两种:阻塞挂起状态,进程在外存中等待某个事件的出现;
就绪挂起状态,进程在外存中,当进入内存后即可运行;
挂起实质上是把一个进程从内存转移到外存中;
常见挂起状态的转换如下:
① 阻塞→阻塞挂起:没有进程处于就绪状态或就绪进程要求更多的内存资源时,会发生这种转换以提交新进程或运行就绪进程;
② 就绪→就绪挂起:当有高优先级(系统认为其很快就绪)阻塞进程和低优先级就绪进程时,系统会将这个低优先级的就绪进程挂起;
③ 运行→就绪挂起:对于抢先式分时系统,当有高优先级阻塞挂起进程因事件出现而进入就绪挂起时,系统会把当前运行的进程转换为就绪挂起状态;
④ 阻塞挂起→就绪挂起:发生在外存中,当阻塞挂起进程由于相关事件出现时,系统会把阻塞挂起进程转换为就绪挂起进程;
解挂/激活标识把一个进程从外存转到内存中,一般有以下情况:
① 就绪挂起→就绪:没有就绪进程或就绪挂起进程优先级高于就绪进程时,会把就绪挂起进程转换为就绪进程;
② 阻塞挂起→阻塞:当一个进程释放足够内存时,系统会把一个高优先级阻塞挂起进程转换为阻塞进程;
操作系统通过PCB、定义的进程状态,基于状态队列来管理和调度不同状态的进程;不同的状态分别用不同的队列来表示(例如就绪队列、阻塞队列等);
每个进程的PCB根据其状态会将进程加入到相应的队列当中,当一个进程的状态发生变化时,它的PCB会从一个状态队列中脱离出来,加入到另一个队列当中;
2--线程
2-1--线程基本概念
线程表示进程当中一条执行流程;进程可以理解为将一组相关的资源(代码段、数据段等)组合起来构成一个资源平台,而线程表示代码在这个资源平台上的一条执行流程;
因此线程可以理解为:线程 = 进程 - 共享资源
线程的优点:
① 一个进程可以同时存在多个线程;
② 各个线程之间可以并发地执行;
③ 各个线程之间可以共享地址空间和文件等资源;
线程的缺点:
一个线程崩溃,会导致其所属进程的所有线程崩溃(安全性问题);
2-2--进程与线程的比较
① 进程是资源分配的单位,而线程是CPU的调度单位;
② 进程拥有一个完整的资源平台,线程只独享必不可少的资源,如上图中的寄存器和堆栈;
③ 线程同样拥有就绪、阻塞和执行三种基本状态,也具有状态之间的转换关系;
④ 线程能减少并发执行的时间和空间开销:
线程的创建和终止时间比进程短;
同一进程内的线程切换时间也比进程短;
由于同一进程的各个线程间共享内存和文件资源,所以可以不通过内核的通信;
2-3--线程的实现
线程的实现方式主要有三种:
① 用户线程:线程在用户空间实现;(操作系统无法感知进程的用户线程)
② 内核线程:线程在内核实现;
③ 轻量级进程:在内核中实现,支持用户线程;
用户线程:
在用户空间中实现的线程机制,其不依赖于操作系统的内核,由一组用户级的线程库函数来完成线程的管理,包括进程的创建、终止、同步和调度等;
用户线程的维护由相应进程通过线程库函数来完成,每个进程拥有私有的线程控制块(Thread Control Block,TCB)列表,用于跟踪记录各个线程的状态信息,TCB由线程库函数来维护;
用户线程的切换通过线程库函数来完成,无需用户态和核心态的切换,因此速度较快;
允许每个进程拥有自定义的线程调度算法;
用户线程的缺点:
当一个用户线程发起系统调用而阻塞时,该进程内所有的用户线程都会被阻塞,从而导致整个进程处于等待状态;(因为操作系统无法感知到进程内部的用户线程,只能感知进程,因此只会对进程进行阻塞)
当一个线程开始运行时,除非主动交出CPU使用权,否则其所在的进程当中任何线程都无法运行;(因为用户态的线程库无法主动打断线程的运行)
时间片分配给进程,在多线程执行时,进程的每个线程获取的时间片更少,因此执行会较慢;(内核线程,直接分配时间片给线程,因此执行更快)
内核线程:
在操作系统内核当中实现的一种线程机制,由操作系统的内核来完成线程的创建、终止和管理;
在支持内核线程的操作系统当中,由内核来维护进程和线程的上下文信息(PCB和TCB);
内核线程的创建、终止和切换都是通过系统调用/内核函数的方式来进行,由内核完成,因此系统开销较大;
在一个进程当中,如果一个内核线程发起系统调用被阻塞,并不会影响其他内核线程的执行;
操作系统直接分配时间片给内核线程,因此多线程的进程会获取更多的CPU时间;
轻量级进程:
轻量级进程是内核支持的用户线程,一个进程可拥有一个或多个轻量级进程,每个轻量级进程由一个单独的内核线程来支持;
3--进程控制
3-1--进程切换
进程切换:停止当前运行进程(当前运行进程从运行状态变成阻塞、就绪等状态),调度其它进程(其它进程变成运行状态);
进程切换必须存储进程的上下文,便于后续重新恢复;
存储的上下文包括寄存器、CPU状态等;上下文的转换也必须迅速;
3-2--进程创建、加载和执行
folk(): 进程可以通过调用 folk() 函数来创建新的进程,调用进程称为父进程,创建的新进程称为子进程;folk() 函数会复制父进程的内存映像到子进程中,即子进程相当于父进程的一个副本,其代码内容相同;
exec(): 一般调用 folk() 函数创建新进程后,希望新进程执行新的程序内容,而 folk() 函数会将父进程的内存映像复制到子进程中,并不会为新进程加载新的内存映像;因此在绝大数情况下,调用 folk() 函数创建新进程后会调用exec()函数,其用于为新进程加载一份新的内存映像,即更新其程序内容使其执行新的功能;
3-3--进程等待和终止
wait(): 父进程调用 folk() 创建新进程后,父进程和子进程会并发执行;这时父进程可以通过 wait() 函数使其自身阻塞,直到子进程结束;wait() 函数会导致父进程暂停执行,直到子进程的状态可用或父进程接收到一个信号为止;
exit(): 上面提到父进程通过wait()函数暂停执行,直到接收到一个信号为止;而exit()函数由子进程调用,用于子进程的结束,此时会返回一个信号给父进程,让父进程知晓子进程结束并帮助子进程回收相应的进程资源;