进程和线程
进程描述
1.1 进程的定义
进程:一个具有一定独立功能的程序在一个数据集合上的一次动态执行过程。
1.2 进程的组成
一个进程包括:
- 程序的代码
- 程序处理的数据
- 程序计数器的值,执行下一条将运行的指令
- 寄存器
- 系统资源
进程包含了正在运行的一个程序的所有状态信息
进程和程序的关系:
- 程序是产生进程的基础
- 程序每次运行构成不同的进程
- 进程是程序功能的体现
- 通过多次运行,一个程序可以对应多个进程;通过调用关系,一个进程可包含多个程序
进程和程序的区别:
- 进程是动态的,程序是静态的:程序是有序代码的集合;进程是程序的执行,进程有用户态/核心态
- 进程是暂时的,程序是永久的:进程是一个状态变化的过程,程序可永久保存
- 进程和程序的组成不同:进程的组成包括程序、数据和进程控制块(进程状态信息)
1.3 进程的特点
- 动态性:可动态的创建、结束进程
- 并发性:在一段时间内有多个进程在执行叫做并发;并行是在一个时刻有多进程能够执行
- 独立性:不同进程的工作不相互影响
- 制约性:因访问共享数据/资源或进程间同步而产生制约
设计一个OS,怎么实现其进程管理机制?
1.4 进程控制结构
进程控制块:操作系统管理控制进程运行所用的信息集合
使用进程控制块:
- 进程的创建
- 进程的结束
- 进程的组织管理
PCB包括三类信息:
- 进程标识信息
- 处理器状态信息
- 进程控制信息
PCB的组织方式:
- 链表(常用)
- 索引表
进程状态
2.1 进程的生命期管理
- 进程创建
系统初始化
用户请求创建一个新进程
正在运行的进程执行了创建进程的系统调用 - 进程运行
内核选择了一个就绪进程,让它占用处理机并执行 - 进程等待
进程只能自己阻塞自己 - 进程唤醒
进程只能被别的进程或操作系统唤醒 - 进程结束
正常退出、错误退出、致命错误、被其他进程kill
2.2 进程状态变化模型
- 运行状态
- 就绪状态
- 等待状态(阻塞状态)
进程的其他状态:创建状态、结束状态
2.3 进程挂起
进程在挂起状态时,意味着进程没有占用内存空间。处于挂起状态的进程映像到磁盘上
挂起状态:
- 阻塞挂起状态
- 就绪挂起状态
与挂起相关的状态转换:
挂起:把一个进程从内存转到外存
- 阻塞到阻塞挂起
- 就绪到就绪挂起
- 运行到就绪挂起:抢先式分时系统
- 在外存的状态转换:阻塞挂起到就绪挂起
解挂/激活:把一个进程从外存转到内存
- 就绪挂起到就绪
- 阻塞挂起到阻塞
OS怎么通过PCB和定义的进程状态来管理PCB,帮助完成进程的调度过程?
状态队列:
- 由操作系统来维护一组队列,用来表示系统当中所有进程的当前状态
- 不同的状态分别用不同的队列来表示
- 每个进程的PCB都根据它的状态加入到相应的队列当中
线程管理
3.1 为什么使用线程
原因是:进程之间如何通信,共享数据,维护进程的系统开销很大:创建进程时,分配资源,建立PCB;撤销进程时,回收资源,撤销PCB;进程切换时,保存当前进程的状态信息
线程之间并发的执行,共享相同的地址空间
3.2 什么是线程
线程:进程当中的一条执行流程
从两个方面重新理解进程:
1、从资源组合角度:进程是一个资源平台
2、从运行角度:代码在资源平台上的一条执行流程
线程 = 进程 - 共享资源
线程的优点:
1、一个进程中可以同时存在多个线程
2、各个线程之间可以并发的执行
3、各个线程之间可以共享地址空间和文件等资源
线程的缺点:一个线程崩溃,会导致其所属进程的其他线程崩溃
强调性能时需要用线程来执行,强调安全性时需要用进程来执行
进程和线程的比较:
- 进程时资源分配单位,线程是CPU调度单位
- 进程是一个完整的资源平台,而线程只独享必不可少的资源
- 线程同样具有就绪、阻塞和执行三种基本状态,同时具有状态之间的转换关系
- 线程能减少并发执行的时间和地址开销
3.3 线程的实现
- 用户线程:操作系统看不到的线程
- 内核线程:由操作系统管理的线程
- 轻量级进程
用户线程和内核线程之间的关系:
- 多对一
- 一对一
- 多对多
在用户空间实现的线程机制,它不依赖于操作系统的内核,由一组用户级的线程库函数来完成线程的管理,包括进程的创建、终止、同步和调度等
用户线程缺点:
- 如果一个线程发起系统调用而阻塞, 则整个进程在等待
- 当一个线程开始运行后,除非它主动地交出CPU的使用权,否则它
所在的进程当中的其他线程将无法运行 - 由于时间片分配给进程,故与其它进程比,在多线程执行时,每个 线程得到的时间片较少,执行会较慢
内核线程是指操作系统的内核当中实现的一种线程机制,由操作系统的内核来完成线程的创建、终止和管理
上下文切换
停止当前运行进程(从运行状态转换为其他状态)并且调度其他进程(转为运行状态)
信号量
抽象数据类型:
- 一个整形(sem),两个原子操作
- P():sem减1,如果sem小于0,等待,否则继续
- V():sem加1,如果sem小于等于0,唤醒一个等待的P
信号量类似于铁路
Dijkdstra 在20世纪60年代提出
在早期的操作系统中是主要的同步原语
信号量的使用
- 信号量是整数
- 信号量是被保护的变量
- P() 能够阻塞,V()不会阻塞
- 两种类型信号量
1、二进制信号量:0或1
2、一般/计数信号量:非负 - 信号量可以用在两个方面
1、互斥
2、条件同步
- 在任何时间只能有一个线程操作缓冲区(互斥)
- 当缓冲区为空,消费者必须等待生产者(调度/同步约束)
- 当缓冲区满,生产者必须等待消费者(调度/同步约束)
每个约束用一个单独的信号量
信号量的实现
-
使用硬件原语
禁止中断、原子指令 -
类似锁
-
信号量的双用途:
1、互斥和条件同步
2、等待条件是独立的互斥 -
读/开发代码比较困难
程序员必须非常精通信号量 -
容易出错
1、使用的信号量已经被另一个线程占用
2、忘记释放信号量 -
不能够处理死锁问题
管程
- 目的:分离互斥和条件同步
- 什么是管程
1、一个锁:指定临界区
2、0或多个条件变量:等待/通知信号量用户管理并发访问共享数据 - 一般方法
收集在对象/模块中的相关共享数据
定义方法来访问共享数据
- 实现
需要维持每个条件队列
线程等待的条件等待signal()
- 开发/调试并行程序很难
- 同步结构
锁:互斥
条件变量:有条件的同步
其他原语:信号量
死锁
死锁问题
一组阻塞的进程持有一种资源等待获取另一个进程所占有的一个资源
系统模型
- 资源类型R1, R2, … , Rm
CPU、内存、I/O - 每个资源类型 Ri 有 Wi 实例
- 每个进程使用资源如下:
request/get
use/hold
release
可重复使用的资源
- 在一个时间只能一个进程使用且不能被删除
- 进程获得资源,后来释放由其他进程重用
- 处理器、I/O ,主和副村春旗、设备和数据结构,如文件、数据库和信号量
- 如果每个进程有一个资源并请求其它资源,死锁可能发生
使用资源:
- 创建和销毁
- 在 I/O 缓冲区的中断,信号,消息,信息
- 如果接受消息阻塞可能会发生死锁
- 可能少见的组合事件会引起死锁
- 如果图中不包含循环——没有死锁
- 如果图中包含循环
如果每个资源类只有一个实例,那么死锁
如果每个资源类有几个实例,可能死锁
死锁特征
死锁的四个必要条件:
- 互斥:在一个时间只能有一个进程使用资源
- 持有并等待:进程保持至少一个资源正在等待获取其他进程持有的额外资源
- 无抢占:一个资源只能被进程自愿释放
- 循环等待
死锁处理办法
- 死锁预防
- 死锁避免
- 死锁检测
- 死锁恢复
死锁预防和死锁避免
- 最简单和最有效的模式是要求每个进程声明它可能需要的每个类型资源的最大数目
- 资源的分配状态是通过限定提供与分配的资源数量,和进程的最大需求
- 死锁避免算法动态检查的资源分配状态,以确保永远不会有一个环形等待状态
- 当一个进程请求可用资源,系统必须判断立即分配是否能使系统处于安全状态
- 系统处于安全状态是指,针对所有进程,存在安全序列
死锁检测和死锁恢复
- 允许系统进入死锁状态
- 死锁检测算法
- 恢复机制
死锁恢复: - 终止所有的死锁进程
- 在一个时间内终止一个进程直到死锁消除
- 终止进程的顺序
1、进程的优先级
2、进程运行了多久以及需要多少时间才能完成
3、进程占用的资源
4、进程完成需要的资源
5、多少进程需要被终止
6、进程是交互还是批处理
进程间通信 IPC
概述
- IPC 设备提供两个操作
send:消息大小固定或可变
receive - 如果两个进程之间通信,需要
在它们之间建立通信链路
通过send/receive交换消息 - 进程链路的实现
物理(共享内存、硬件总线)
逻辑
直接通信
- 通信必须正确命名对方
- 通信链路的属性
1、自动创建链路
2、一条链路对应一对通信进程
3、每对进程之间只有一条链路存在
4、链接可以是单向的,也可以是双向的
间接通信
-
定向从消息队列接收消息
每个消息队列都有一个唯一的ID
只有通信双方共享了一个消息队列,进程之间才能通信 -
通信链路的属性
只有进程共享同一个消息队列,才建立链路
链路可以与许多进程相关联
每对进程可以共享多条链路
连接可以是单向或双向 -
创建一个新的消息队列
-
通过消息队列发送和接收消息
send:发送消息到队列A
receive:从队列A接收消息 -
销毁消息队列
-
消息传递可以是阻塞或非阻塞
-
阻塞被认为是同步的
-
非阻塞被认为是异步的
-
队列的消息被附加到链路:
1、0 容量:发送方必须等待接收方
2、有限容量:发送方必须等待,如果队列满
3、无限容量:发送方不需要等待
信号
- Signal
软件中断通知事件处理 - 接收到信号时会发生什么
Catch:指定信号处理函数被调用
Ignore:依靠操作系统的默认操作
Mask:闭塞信号,不会发送 - 缺点
不能传输要交换的任何数据
管道
进行数据交换
- 子进程从父进程继承文件描述符
0:标准输入,1:标准输出,2:标准错误输出 - 进程不知道从键盘、文件、程序读取或写入到终端,文件,程序
- 例:ls | more
消息队列
- 消息队列按 FIFO(先进先出)来管理消息
共享内存
直接通信的方式
- 进程
每个进程都有私有地址空间
在每个地址空间内,明确的设置了共享内存段 - 优点
快速、方便的共享数据 - 缺点
必须同步数据访问