开始13180 操作系统的学习过程,献给每一位拥有梦想的"带专人",
ps:有不正确的地方麻烦更新在评论区,我会一一修复 😅
第二章 进程/线程模型
1. 进程
进程是具有一定独立功能的程序在某个数据集合上运行的活动,是操作系统进行资源分配和调度的单位
从操作系统的角度来看,可将进程分为用户进程和系统进程,系统进程的优先级高
进程与程序的区别与联系
-
进程和程序的联系
程序是进程的组成部分之一,一个进程的目标是执行它所对应的程序,如果没有程序进程就失去了意义。从静态角度来看,进程是由程序、数据和控制块(PCB)组成的
-
进程与程序的区别
程序是静态的,进程是动态的。
程序是永久存在的,进程是为了程序的一次执行而短暂存在的
一个进程可以包含若干程序的执行,一个程序也可以产生多个进程。
进程具有创建其它进程的功能。被创建的进程称为子进程,创建者称为父进程。
例如:一个编译程序在执行时就要执行词法分析、语法分析、代码生成和优化等若干个程序。而一个编译程序有时需要同时生成几个编译进程,为几个用户服务。
可再入程序
一个能被多个用户同时调用的程序,在执行中自身不可以改变
通俗讲:可再入程序必须和有关的数据区分离
进程的特征
-
并发性:
多个进程可以同时运行,互不干扰。
-
动态性:
进程有生命周期,从创建到消亡,状态会不断变化。
-
独立性:
每个进程是独立的资源分配和运行单位。
-
交互性:
进程之间可以通过通信或共享资源进行交互。
-
异步性:
进程独立运行,进度不可预测。
-
结构性:
由程序、数据和控制信息(PCB)组成。
并动态交互,异步独立结构
2. 进程状态及状态转换
三状态进程模型
-
运行状态
进程已获得 CPU 并已在 CPU 上执行。在单 CPU 系统,最多只有一个进程处于运行状态
-
就绪状态
已满足运行条件,但因未获得 CPU 而等待分配。多个进程可同时处于就绪状态。
-
阻塞状态
也称
等待状态或封锁状态,因等待资源或事件而暂停运行(如等待文件输入或竞争资源失败)。等待条件消失后,转为就绪状态,可再次争取 CPU。
状态转换
-
就绪 → 运行:
就绪进程因获得 CPU 开始运行,调度程序按算法分配 CPU,并启动进程运行。
-
运行 → 就绪:
时间片耗尽,触发超时中断,保存进程现场,将其状态设为就绪,等待重新调度。
-
运行 → 阻塞:
进程因等待资源(如文件输入)暂停运行,保存现场,标记阻塞原因,CPU 转给其他就绪进程。
-
阻塞 → 就绪:
阻塞条件解除,进程转为就绪,等待 CPU 分配后继续运行。
五状态进程模型
-
运行状态:
已获得 CPU 资源,正在执行代码。
当系统无其他可运行进程时,执行系统的空闲进程
-
就绪状态:
已具备运行条件,等待 CPU 分配。
就绪进程通常按优先级排队,可能形成多个优先级队列。
-
阻塞状态:
因等待 I/O 或同步事件暂停执行,即使分配到 CPU 也无法运行。
进入阻塞队列,按事件分类,等待条件解除。
-
创建状态:
系统为进程分配资源、加载程序、建立控制块,但进程尚未投入运行
-
退出状态:
进程执行结束,系统回收资源并传递相关信息给父进程。
操作系统中多个进程的并发执行时通过交替进入运行状态来实现的
五状态模型状态转换方式
- 调度与超时:当一个运行状态的进程超时后,放入
低优先级就绪队列,并修改其状态为就绪状态,然后调度另一个就绪状态的进程进入运行状态 - 调度、等待事件、事件出现:当一个处在运行状态的进程需要等待某个事件的发生时,主动放弃 CPU,进入阻塞状态;调度另一个就绪状态的进程进入运行状态,当上一个进程等待的事件出现后将相应从阻塞状态队列取出,放入
高优先级就绪队列,将状态改为就绪状态
状态转换:
-
创建新进程:
产生一个新进程,用于运行某程序,例如用户登录或系统创建服务。
-
提交:
新进程创建完成,进入就绪状态等待 CPU 分配。
系统可能限制并发进程数以优化性能。
-
调度运行:
从就绪队列中选择进程分配 CPU,进入运行状态。
-
释放:
进程因完成任务或出现问题终止,进入结束状态
正常退出:任务完成。
异常退出:如内存不足、非法操作或被其他进程终止。
-
超时:
时间片用尽或高优先级进程抢占 CPU,当前进程暂停运行,返回就绪状态。
-
事件等待(进入阻塞状态):
等待资源或事件(如 I/O 操作、通信),暂时无法继续执行。
-
事件出现(进入就绪状态):
等待的事件完成或条件满足,阻塞状态解除,返回就绪队列。
七状态进程模型
五状态进程模型没有区分进程地址空间是外存还是内存,在操作系统中引入虚拟存储管理技术后,需要进一步区分进程的地址空间状态
出现的原因:由于进程之间存在优先级,低优先级的进程等待时间可能较长,为了内存充足,将低优先级的进程移动到外存
优点:
-
提高处理机效率:
就绪队列为空时,可利用空闲内存提交新进程,提高处理器使用率。
-
灵活内存分配:资源不足时,可将部分进程移至外存,为运行进程腾出内存。
-
有利于调试:调试时可挂起目标进程,方便对其地址空间进行操作。
对比五状态进程模型增加了两个状态
- 就绪状态:进程在
内存且可立即进入运行状态 - 阻塞状态:进程在
内存并等待某事件的出现 - 阻塞挂起状态:进程在
外存并等待某事件出现 - 就绪挂起状态:进程在
外存,但只要进入内存,即可运行
七状态进程模型中,新引入的状态转换有挂起和激活两类,意义有变化的转换有事件出现和进程提交
-
挂起:进程从内存移到外存
阻塞到阻塞挂起:内存不足时,为提交新进程或运行就绪进程。
就绪到就绪挂起:有高优先级阻塞,挂起低优先级就绪进程。
运行到就绪挂起:抢占式系统中,为高优先级进程腾内存。
-
激活:进程从外存移回内存
就绪挂起到就绪:优先级高于当前就绪进程或无就绪进程。
阻塞挂起到阻塞:内存释放,且事件可能即将出现。
-
事件出现:进程等待的事件发生
阻塞到就绪:事件满足,内存中的进程。
阻塞挂起到就绪挂起:外存中进程的事件满足。
-
进程提交:完成新进程创建,进入就绪或就绪挂起状态(维持较大就绪队列)。
3. 进程控制块
为了便于系统控制和描述进程的活动过程,在操作系统内核中定义了一个专门的数据结构,称为进程控制块 PCB
PCB 的内容
- 调度信息:进程名和进程号共同标识一个进程,一个进程的进程号必须是唯一的
- 现场信息:进程的运行情况,每个进程都有自己的专用的工作存储区,其他进程运行时不会改变它的内容
进程的组成
进程由程序、数据和 PCB 三部分组成,PCB 是进程的灵魂,程序和数据是进程的躯体
PCB 的组织方式
-
线性方式:
将所有 PCB 不分状态组织在一个连续的表中
优点是简单不需要额外的开销,适用于进程数目不多的系统
缺点是需要扫描整个 PCB 表才能找到需要的PCB
-
索引方式:
具有相同状态的进程,分别设置各自的 PCB 索引表
- 链接方式:指针
进程队列的分类
-
就绪队列
所有就绪状态的进程都排在就绪队列中
-
等待队列
对于每一个等待事件组成一个队列
-
运行队列
在单 CPU 系统中,整个系统有一个运行队列
进程队列的组成
进程队列可以用进程控制块的链接来形容
常用的链接方式有单向链接(C 语言的单链表)、双向链接(C 语言中的双向链表)
一个进程从所在队列中退出称为出队
一个进程排入指定队列称为入队
一个进程插入某个进程队列中间称为插队
进程出队的具体过程
- 队首进程出队
- 非队首(或队尾)进程出队
- 队尾进程出队
4. 进程控制
进程有一个从创建到消亡的生命周期,需要对进程的生命周期中的各种状态转换进行控制,称为进程控制。进程控制是通过进程控制原语实现的
原语
由若干条指令组成的指令序列,用来实现某个特定的操作功能。这个指令序列的执行是连续的,具有不可分割性,执行时也不可以间断,直至该指令执行结束
原语必须在内核态下执行,并且常驻内存。
原语和系统调用都可以被进程所调用,两者的差别在于原语具有不可中断性,它是通过其执行过程中关闭中断实现的,而且原语往往被系统进程所调用
用于进程创建的原语一般由创建原语、撤销原语、挂起原语、激活原语、阻塞原语、唤醒原语、改变进程优先级原语
-
创建原语:
创建一个新的进程。创建一个进程的主要任务是建立 PCB。
创建进程的具体操作是:先申请一个空闲 PCB 区域,将有关信息填入 PCB,置该进程为就绪状态,将其插入就绪队列中
-
撤销原语:
释放进程所占用资源,撤销进程实质上就是撤销 PCB
-
阻塞原语:
进程从运行状态转换为阻塞状态
-
唤醒原语:
一个进程因为等待某个事件而发生阻塞,当该事件发生后,使用唤醒原语将该进程转化为就绪状态
5. 线程
线程的引入
进程是调度的基本单位还是独立分配资源的单位,如果可以将这两个基本单位的功能分开,即作为调度和分派的基本单位,不作为独立分配资源的单位,则可以让进程轻装运行,面对拥有资源的基本单位,不频繁的对其进行切换,可以提高并发程度并避免消耗过多的系统资源
什么是线程
线程是进程中的一个实体,是CPU调度和分派的基本单位(重点)。
• 资源:线程自身只拥有少量资源(如程序计数器、寄存器和栈),但可以共享进程的全部资源。
• 特性:线程之间可并发执行,同一进程的线程可相互创建和撤销(重点)。
线程的属性
-
唯一标识与描述表:
每个线程有唯一标识符和线程描述表,记录其执行的寄存器、栈等状态信息(重点)。
-
执行独立性:
不同线程可以执行相同程序,例如同一个服务被多个用户调用时,系统为其创建多个线程(重点)。
-
共享内存:
同一进程内的线程共享进程的内存空间(重点)。
-
调度单位:
线程是独立的调度单位,支持并发执行:
• 单处理器系统:线程交替占用 CPU。
• 多处理器系统:线程可并行运行,减少总时间(重点)。
-
生命周期:
线程从创建到终止,会经历阻塞、就绪、运行三种状态(重点)。
简化总结:线程是共享进程资源的调度单位,有独立标识和状态描述表,支持并发和并行,生命周期包含阻塞、就绪、运行三种状态。
引入线程的好处
-
创建快,开销低:
创建线程无需分配资源,比创建进程更快,系统开销更少(重点)。
-
切换效率高:
线程间切换速度比进程切换快(重点)。
-
通信高效:
同一进程内线程共享内存和文件,线程通信无需调用内核,速度快、机制简单(重点)。
-
并行能力强:
线程可独立执行,充分利用处理器和外部设备的并行工作能力(重点)。
简化总结:线程的创建、切换速度快,通信简单高效,并能充分发挥并行性能。
线程的组成
线程控制块 (thread 结构) 简化版
用于保存线程私有信息。
组成
1. 线程描述符:唯一标识线程的编号。
2. 寄存器组:记录线程运行状态,包括程序寄存器、状态寄存器、通用寄存器。
3. 双栈指针:
• 内核栈指针:线程切换到内核态时使用。
• 用户栈指针:线程在用户态执行时使用。
4. 私有存储区:存储线程的现场保护信息和相关统计数据。
记忆重点
线程控制块包含 唯一描述符、寄存器组、双栈指针、私有存储区。
线程必须在某个进程内执行,它所需的资源都由它所属的进程拥有,操作系统分配资源时以进程为单位
一个进程可以包含多个线程。传统的进程只有一个线程。当一个进程包含多个线程时,这些线程,除各自私有的少量资源外,还要共享所属进程的所有资源
线程与进程的关系
线程具有许多传统进程所具有的特征,所以线程又称为轻量级进程或进程元;传统的进程称为重量级进程
线程与进程比较
-
调度:
线程是 CPU 调度的基本单位,进程是资源分配的基本单位
-
并发性:
引入线程后,操作系统的并发性变得更强
-
拥有资源:
只有进程才拥有资源,一个进程中的所有线程共享进程中的资源
-
系统开销:
线程调度的系统开销远小于进程调度的系统开销
线程的实现方式
线程的分类
- 用户级线程
用户级线程由应用程序管理,与操作系统内核无关。
存在于用户空间:线程创建、切换、撤销均在用户空间完成,无需依赖系统调用。
内核感知:内核无法识别用户级线程,仅管理普通进程。
优点:
- 切换速度快:线程切换无需陷入内核,性能高效。
- 灵活调度:应用程序可使用专用调度算法,满足特殊需求。
- 兼容性强:适用于任何操作系统,包括不支持线程机制的系统。
缺点:
- 阻塞问题:
- 典型系统调用为阻塞式。
- 当某线程因系统调用阻塞时,同一进程内所有线程均被阻塞。
- 多处理器劣势:
- 单用户级线程在多处理器系统中无法并行,内核一次仅为一个进程分配一个处理器。
- 同一进程内其他线程需等待当前线程释放 CPU。
记忆重点
优点:切换快、灵活调度、跨系统兼容。
缺点:阻塞影响整体、无多处理器优势。
- 内核级线程
线程的创建、切换和管理均由操作系统内核负责,内核感知线程的存在并通过线程控制块(TCB)进行管理。
特点
• 依赖内核:线程操作(如创建、撤销、调度)均需通过内核完成。
• 系统支持:内核为每个线程保留独立的线程控制块,以感知和管理线程。
优点:
-
多处理器并行支持:
在多处理器系统中,内核能同时调度同一进程中的多个线程,实现真正的并行操作
-
阻塞问题缓解:
若进程内一个线程阻塞,内核可调度该进程中的其他线程继续执行。
-
内核线程本身可多线程
支持高并发任务处理。
缺点:
-
切换开销大:
线程切换需从用户态转至内核态,增加控制转移的成本。
-
固定调度算法:
线程调度由内核控制,应用程序无法自定义线程切换策略。
记忆重点
优点:多处理器支持、阻塞可切换、线程并发高效。
缺点:切换耗时、调度算法受限。
-
混合方式实现的线程
线程创建在用户空间完成,线程调度在核心空间完成
线程实现方式的比较:
-
线程的调度与切换速度
用户级线程切换的速度特别快
-
系统调用
-
用户级线程
行为:
用户级线程的系统调用由进程控制,内核不了解用户级线程的存在。
结果:
- 当一个线程执行系统调用时,内核认为这是整个进程的行为,因此会阻塞整个进程。
- 其他线程无法执行,导致低效率。
-
内核级线程
行为:内核感知线程的存在,系统调用被识别为单个线程的行为。
结果:
- 当某线程因系统调用被阻塞时,内核可调度同一进程的其他线程运行。
- 提升并发度和系统资源的利用率。
-
-
线程执行时间
- 用户级线程系统,调度是以进程为单位的
- 内核级线程系统,调度是以线程为单位的
-
6. 协程
当线程的数量非常大的时候,系统线程会占用非常多的内存空间,过多的线程切换会占用大量的系统时间。为了解决这两个问题,许多编程语言提出了协程机制,例如 C++语言、Python 语言、Go 语言。
协程是运行在线程之上的轻量级线程,当一个协程执行完成后,可以选择主动退出,让另一个协程运行在当前线程之上。协程并没有增加线程的数量,只是在线程的基础上通过分时复用的方式运行多个协程,而且协程的切换在用户态完成,切换的代价比线程从用户态到内核态的代价小很多
练习
-
当阻塞队列中唯一的一个进程所等待的事件发生后,该进程应转变为
- 运行状态
- 就绪状态
- 阻塞状态
- 退出状态
对于处于等待状态的进程,在其被阻塞的原因获得解除后,其状态将变为就绪,仅当得到CPU是,才可恢复运行
-
某进程已获得处理器外的所有资源,正等待分配处理器资源,此时进程处于
- 运行状态
- 创建状态
- 等待状态
- 就绪状态
-
正在运行的进程,由于规定的时间片用完而使得系统发出超时中断请求,此时进程状态被修改为
- 就绪状态
- 阻塞状态
- 就绪挂起状态
- 阻塞挂起状态
-
为了实现对进程的管理,系统通常将相同状态的进程分别组成就绪队列、等待队列和运行队列
-
原语和系统调用都可以被进程所调用,两者的差别在于原语具有不可中断性,它是通过在其执行过程中关闭中断来实现的
-
进程控制通常采用原语来实现,当某进程在执行过程中需要执行 I/O 操作时,系统使用阻塞原语;当进程所等待的事件发生后,系统使用唤醒原语将其转换为就绪状态
-
以下关于线程的属性的叙述中,正确的是
- 每个线程有多个标识符和一张线程描述表
- 同一个进程中的各个线程共享该进程的内存地址空间
- 不同的线程不可以执行相同的任务
- 多个线程是不可以并发执行的
-
以下关于引入线程的好处叙述中,不正确的是
- 线程能独立执行
- 线程之间切换花费时间少
- 创建一个新线程花费的时间少
- 线程之间相互通信包含多种通信机制
-
同一个进程的多个线程共享该进程的内存地址空间和文件,它们之间的同步和通信无需调用内核,实现容易且开销小
-
为实现进程管理,系统采用链接方式对所有的进程控制块(PCB)进行组织。其中,单向链接方式只有一个指针,前一进程的PCB中的指针值为下一个进程的PCB的地址;双向链接方式包含2 个指针,分别指向前一个进程的地址和后一个进程的 PCB 地址。
-
对于只设置了用户级线程的系统,调度的进行单位是
- 线程
- 管程
- 通道
- 进程
-
线程的实现方式不包括
- 混合实现方式
- 内核级线程
- 商业级线程
- 用户级线程
-
以下关于用户级线程的叙述中,不正确的是
- 用户级线程依赖于内核
- 用户级线程只存在于用户态中
- 用户级线程包可以在不支持线程的操作系统上实现
- 用户级线程允许每个进程有自己定制的调度算法
-
内核级线程的创建、撤销和切换由内核实现,每个进程都对应一个线程控制块,系统根据它来感知线程的存在并对它进行控制
-
在线程的两种实现方式中,不依赖于内核的是用户级线程,而所有线程的创建、撤销和切换都由内核实现的是内核级线程
-
以下关于线程的陈述中,错误的是
- 内核不知道用户级线程的存在
- 无论何种线程,其切换都需要内核的支持
- 在支持线程的系统中,线程是调度和分派的基本单位
- 无论系统是否支持线程,进程都是资源分配的基本单位
捏捏捏捏捏捏捏捏捏捏捏
笔者观看的课程是 B 站博主小飞学长Pro的 课程,前四章是免费的如果需要看后面的建议大家去购买正版课程 😊😊
🎉 🎉 🎉 🎉 🎉 🎉 🎉 🎉 🎉 🎉 🎉 🎉 🎉 🎉 🎉 🎉 🎉 🎉 🎉 🎉 🎉 🎉 🎉 🎉