文章目录
进程控制
什么是进程控制
- 创建, 撤销进程, 实现进程间的状态转换
- 就是实现进程间状态转换 (因为创建撤销进程也属于两种状态, 创建态, 终止态)
如何实现进程控制
- 进程组织
- 处于不同状态的进程会被放入对应的队列中, 使用一个相应的指针指向这些队列首地址
- 处于不同状态的进程会被放入对应的队列中, 使用一个相应的指针指向这些队列首地址
- 创建进程 : 初始化PCB, 分配系统资源
- 创建态->就绪态 : 修改PCB内容, 转移到相应的队列
- 就绪态->运行态 : 恢复进程运行的环境, 修改PCB内容, 转移到相应的队列
- 运行态->阻塞态 : 保存当前运行环境, 修改PCB内容, 转移到相应队列
- 阻塞态->就绪态 : 修改PCB内容, 转移到相应的队列, 分配需要的资源
- 运行态->就绪态 : 修改PCB内容, 转移到相应队列
- 运行态->终止态 : 回收资源, 撤销PCB
进程的控制, 实际上是对PCB的控制来实现进程状态的转换, 每次转换都涉及到修改PCB相关内容, 转移到相应队列
-
如果在修改PCB内容, 和PCB转移到相应的队列之间出现了中断, 导致PCB内容(状态标识位)和所在队列并不一致, 就会出现意想不到的错误.
- 因此引入了
原语来实现进程控制.- 原语的特点是执行期间不允许中断, 只能一气呵成, 这种操作成为原子操作
- 原语采用
关中断指令和开中断指令实现
- 因此引入了
-
关中断指令执行后, 对外部中断信号会进行忽视
-
开关中断指令的权限非常大, 如果用户程序可以使用, 可能会造成永远霸占CPU资源, 所以他们是只允许在
核心态下执行的特权指令
进程控制相关原语
无论哪种原语, 要做的都只是三类事情
- 更新PCB中的信息
- 修改进程的状态标识位
- 剥夺当前运行进程的CPU使用权时保存其运行环境
- 进程开始运行前恢复其运行环境
- 将PCB转移到合适的队列
- 分配/回收资源
进程的创建
进程的终止
进程的阻塞和唤醒
进程的切换
总结
进程通信
什么是进程通信
- 进程通信 : 进程之间的信息交换
- 进程是系统资源分配的单位(包括内存空间), 因此每个进程的拥有的内存空间地址是相互独立的
- 为了保证安全性, 一个进程不能直接访问另一个进程的地址空间
- 但是进程间的通信又是必须的, 所以为了保证进程间通信的安全性, 操作系统提供了一些方法
- 在网页上看到了一张图片, 点击分享到微信, 微信进程和图片进程或者浏览器进程肯定是有通信的.
- 三种通信方式
- 共享存储
- 消息传递
- 管道通信
共享存储
- 两个进程因为不能直接访问对方的内存空间, 所以操作系统会为他们分配一个共享空间
- 两个进程对共享空间的访问是互斥的
- 互斥需要通过同步互斥工具实现(如PV操作)
- 共享存储分为两种
- 基于数据结构的共享 : 规定了共享空间中的数据形式, 比如一个长度为10的数组.
- 速度慢, 限制多, 低级通信
- 基于存储区的共享 : 操作系统只提供一块共享存储区, 数据的形式, 存放位置都由进程控制, 而不是操作系统.
- 速度快, 高级通信方式
- 基于数据结构的共享 : 规定了共享空间中的数据形式, 比如一个长度为10的数组.
管道通信
- 管道 : 一个特殊的共享文件. 内存当中开辟的一个大小固定的缓冲区 (Linux中4kb)
- 管道只能采用
半双工通信, 某一段时间内只能实现单向的传输(可以从左到右, 也可以从右到左, 但是一段时间内只能有一个方向). 如果要实现双向同时传输, 需要设置两个管道 - 各进程对管道的访问也是
互斥进行的 - 数据以字符流的形式写入管道, 当
管道写满时, 写进程的write()系统调用被阻塞, 等待读进程将数据取走 ; 当读数据全部取走后,管道变空, 此时读进程的read()系统调用被阻塞 - 如果
没有写满, 就不允许读; 如果没读空, 就不允许写; - 管道中的数据一旦被读出, 就从管道中抛弃, 意味着
读进程最多只能有一个, 否则可能会有读错数据的情况
消息传递
- 进程间的数据交换以
格式化的消息为单位. 进程通过操作系统提供的发送/消息/接收消息两个原语进行数据交换
- 消息传递
- 直接通信方式
- 发送进程创建带发送的格式化消息, 通过发送原语发送给目标进程, 挂载到目标进程的
消息缓冲队列, 目标进程通过接收原语依次接收消息
- 发送进程创建带发送的格式化消息, 通过发送原语发送给目标进程, 挂载到目标进程的
- 间接通信方式(信箱通信方式)
- 操作系统会维护一个信箱, 发送进程通过发送原语将格式化消息发送到信箱, 接收进程再从信箱中读取
- 直接通信方式
总结
线程
什么是线程, 为什么引入线程
- 并发性 : 是操作系统中同时存在多个运行着的进程. (比如音乐, QQ, 游戏)
- 但是有的进程还需要同时执行很多事情, 比如QQ(聊天, 发文件, 视频), 而传统的进程只能串行执行一些列代码. 为此, 引入了“线程”, 进一步增加并发度
- 传统的进程是程序执行流的最小单位
- 引入线程后, 线程成为了程序执行流的最小单位, 这些线程可以共享一份代码, 也可以拥有不同的代码
- 进程只作为系统资源分配的基本单元
引入线程机制后的变化
线程的属性
线程的实现方式
用户级线程
- 用户级线程 : 应用程序通过线程库实现.所有
线程的管理工作都由应用程序负责(包括线程的切换)- 用户级线程中, 线程切换可以在用户态下进行, 无需操作系统的敢于.
- 在用户看来有多个线程, 但是操作系统内核看来, 意识不到线程的存在.
- 用户级线程 : 从用户视角看到的线程
内核级线程
- 内核级线程 :
线程的管理工作由操作系统内核完成, 需要在核心态下进行- 内核级线程 : 从操作系统内核视角看到的线程
两者组合
- 操作系统只看得见内核级线程, 内核级线程才是cpu分配的单位
多线程模型
多对一模型
- 多对一模型 : 多个用户级线程对应一个内核级线程, 每个用户进程只对应一个内核级线程
- 优点 : 用户级线程的切换在用户空间即可完成, 不需要切换到核心态, 线程管理系统开销小, 效率高
- 缺点 : 当一个用用户级线程被阻塞后, 整个进程都会被阻塞, 并发度并不高. 多个线程不可在多个处理机上并行运行
- 当前内核级线程在处理某个用户级线程的逻辑, 该用户级线程阻塞时, 该内核级线程也会被阻塞, 由于一个进程只对一个内核级线程, 该进程也会阻塞, 其余用户级线程也会被阻塞
一对一模型
- 一对一模型 : 一个用户级线程对应一个内核级线程, 每个用户进程都有与用户级线程同等数量的内核级线程.
- 优点 : 当一个用户级线程被阻塞时, 该线程对应的内核级线程也被阻塞, 但是别的线程还可以继续执行, 并发能力强. 多线程可以在多核处理机上并行执行
- 一个用户进程占用多个内核级线程, 线程切换由操作系统内核完成, 需要切换到核心态, 线程管理成本高, 开销大.
多对多模型
- 多对多模型 : n个用户级线程映射到m个内核级线程 (n>=m), 每个用户进程对应m个内核级线程
- 克服了多对一模型并发度不高的问题, 一对一模型用户进程占用太多内核级线程, 开销太大的缺点
总结
处理机调度
基本概念
- 当有一堆任务要处理时, 由于资源有限, 这些事情没法同时处理. 就需要确定
某种规则来决定处理这些任务的顺序. 这就是调度问题 - 在多道程序系统中, 进程的数量往往是多余处理机个数的, 这样不可能同时并行地处理各个进程.
- 处理机调度 : 从就绪队列中
按照一定的算法选择一个进程并将处理机分配给他运行, 以实现程序的并发执行.
调度的三个层次
高级调度(作业调度)
- 由于内存空间有限, 无法将用户提交的作业全部放入内存, 需要确定某种规则来决定作业的调入顺序
- 作业调度 : 按一定的原则从
外存上处于后备队列的作业中挑选一个或多个作业给他们分配内存等必要资源. 并建立相应的PCB, 是他们获得竞争处理机的权限 - 高级调度 是
外存(辅存) 和 内存之间的调度. 每个作业只调入一次, 调出一次.作业调入时会建立相应的PCB, 调出时才撤销相应的PCB.- 高级调度主要是指调入的问题. 因为只有调入的实际需要操作系统来确定. 调出时机必然是作业运行结束.
中级调度(内存调度)
-
引入了虚拟存储技术后, 可
将暂时不能运行的进程调至外存等待. 等它重新具备了运行条件且内存又稍有空闲时, 再重新调入内存.提高内存利用率, 系统吞吐量
-
暂时调到外存的进程状态为
挂起状态, PCB并不会一起调到外存, 而是会常驻内存. 因为操作系统还需要通过PCB对这些进程进行监控, 管理. PCB中会记录进程在外存中的位置, 状态等信息.被挂起的进程PCB会被放到挂起队列中. -
内存调度 : 决定将哪个处理挂起状态的进程重新调入内存
- 一个进程可能会被多次调出, 调入. 因此
中级调度的频率比高级调度更高
- 一个进程可能会被多次调出, 调入. 因此
低级调度(进程调度)
- 进程调度 : 按照某种方法和策略从就绪队列中选取一个进程, 将处理机非配给它
- 进程调度是
操作系统最基本的一种调度, 并发运行的基础 - 进程调度的频率很高, 几十毫秒就有一次, 才能实现宏观上的并发执行.
进程的七状态模型
- 就绪挂起 : 当内存空间不够用时, 一些处于就绪态和阻塞态的进程会被调入外存.
- 一些进程运行结束后, 可能会被直接调入外存进入挂起态
- 一些进程刚创建时, 由于内存空间不够, 会先进入就绪挂起态.