进程的描述与控制
前驱图和程序执行
-
前驱图(DAG):有向无循环图,用于描述进程之间执行的前后关系
-
程序执行
-
顺序执行:顺序性、封闭性、可再现性
-
并发执行:
-
间断性
程序在并发执行时,它们共享系统资源,致使这些并发执行的进程之间形成了相互制约关系,从而使进程执行期间出现间断性
-
失去封闭性
-
不可再现性
程序并发执行时,多个程序共享系统资源,因而这些资源状态由多个程序改变,所以程序运行失去封闭性,也会导致失去可再现性
-
-
进程描述
引入进程的目的
为了使程序在多道程序环境下能并发执行,以提高资源利用率和系统吞吐量,并对并发执行的程序加以控制和描述,使得并发执行得以实现
进程是进程实体的运行过程,是系统进行资源分配和调度的基本单位
-
进程的特征
-
结构特征:PCB进程控制块(与进程共存亡)、程序段、相关数据段总称为进程映像(进程实体)
- 正文段:二进制代码和常量
- 数据堆段:动态分配的存储区
- 数据栈段:临时变量
-
动态性:进程的基本特征,进程有一定生命周期,而程序则只是一组有序指令集合
-
并发性:引入进程目的是为了让程序并发执行,而程序是不能并发执行的
-
异步性:进程按各自独立的、不可预测的速度向前推进
-
独立性:独占性是个假象,多人主机,独立性是指一个独立运行的个体
进程实体是一个能独立运行的基本单位,也是系统中能独立调度的基本单位,对于为建立进程的程序不具有独立性
作业 !=进程,作业可能包含很多进程,操作系统内部只存在进程
-
-
进程的三种基本状态
-
就绪状态:获得了除处理机外的一切所需资源
-
执行状态
-
阻塞状态:等待某一事件发生
就绪 —进程调度–》执行—时间片用完–》就绪
就绪 —进程调度–》执行–I/O请求–》阻塞–I/O完成–》就绪-
挂起状态:挂起时:程序段、数据段放在外存,PCB放在内存
一个进程在挂起状态,其状态仍可能改变
-
创建状态、终止状态:都只存在一次,创建状态用于分配资源然后来到就绪态,终止状态回收资源,修改状态,取消内存
一个进程从运行态变成阻塞态是主动行为,而从阻塞态变成就绪态是被动的行为
-
-
进程控制块:进程存在的唯一标志
使程序能够成为并发,独立,动态运行的基本单位
- 信息
- 进程描述信息:进程标识符:内部标识符、外部标识符(用户可见)
- 处理机状态:三态状态字,寄存器、计数器、栈指针
- 进程控制和管理信息
- 资源分配清单
- 组织方式:
- 线性
- 链接(最常用)
- 索引
- 信息
进程控制
进程控制一般由OS的内核中原语实现的
原语:由若干条(特权指令+硬件)指令组成的,用于完成一定功能的一个不可分割的过程,是原子操作
-
进程的创建
-
进程的层次结构
子进程可以继承父进程所拥有的资源,当子进程被撤销时,应将其从父进程那里获得的资源归还给父进程
撤销父进程时,同时必须撤销子进程
-
进程的创建
- 申请空白PCB
- 为新进程分配其运行所需的资源
- 初始化PCB
- 如果进程就绪队列能够接纳新进程,便将新进程插入就绪队列
-
-
进程的终止
- 引起终止的事件
- 正常结束
- 异常结束
- 外界干预
- 终止的过程
- 根据标识符,读出进程状态
- 若处于执行状态,终止执行
- 终止子孙进程
- 将资源归还系统
- 将PCB移除队列
- 引起终止的事件
-
进程的阻塞与唤醒
-
进程阻塞过程
block原语,主动的由执行-》阻塞
-
进程唤醒过程
signal原语,被动的由阻塞-》就绪
-
-
进程的挂起与激活(主体是操作系统)
进程同步
-
基本概念
-
两种形式的制约关系
- 间接相互制约关系(互斥):多个进程对之只能互斥的访问,如共享单车
- 直接相互制约关系(同步):源于进程之间的相互合作,如接力赛
-
临界资源(操作系统所有):必须使用互斥共享的资源、一段时间只允许一个进程访问
-
临界区:访问临界资源的代码段为临界区
while(Ture) { 进入区 //对临界资源进行检查,如果未被访问,设置访问状态,否则则阻塞该进程 临界区 //访问临界资源的代码段 退出区 //设置未访问状态 剩余区 }
-
同步机制规则
- 空闲让进
- 忙则等待
- 有限等待
- 让权等待:释放处理机
-
-
信号量机制
P操作wait(S), V操作signal(S)
-
整型信号量(S代表资源数目)
wait(S) { while (S <= 0); //违反让权等待 S--; } signal(S) { S++ }
-
记录型信号量
typedef struct { int value; struct process_control_block *list; }semaphore; wait(semaphore *S) { S->value--; if (S->value < 0) block(S->list); } sigal(semaphore *S) { S->value++; if (S->value <= 0) wakeup(S->list); // 信号量链表中仍有被阻塞资源,应该唤醒 } /** S.value < 0 : 阻塞挂起的进程数 S.value == 0 :没有进程被阻塞且临界资源为空 S.value > 0 : 空闲临界资源数 */
-
-
信号量应用
-
实现互斥:设置一个互斥信号量mutex
semaphore S = 0 P1() { x; V(S);//实现同步关系 } P2() { ... P(S);//检查是否允许完成 y; }
-
实现前驱(同步)关系
semaphore S = 1 P1() { ... P(S); 进入P1临界区 V(S); } P2() { ... P(S); 进入P2临界区 V(S); }
-
-
管程
-
管程特性保证了进程互斥,无需程序员自己实现互斥
-
组成 部分
- 管程的名称
- 局部于管程内部数据结构实现
- 对该数据结构进行操作的一组过程
- 对局部于管程内部的共享数据结构设置初始值的语句
-
条件变量
-
x.wait类似P操作
-
x.signal类似V操作
不同点时条件变量没有值
-
-
经典进程同步问题
-
生产者-消费者问题
int in, out = 0; item buffer[n]; semaphore mutex = 1, empty = n, full = 0; void producer() { do { produce an item nextp; ... wait(empty); wait(mutex); //如果wait(empty),wait(mutex)换位置,可能出现死锁,先wait(mutex)的话,如果full = n,empty = 0此时无法获得empty锁,且消费者由于无法得到mutex也无法从中取走数据 buffer[in] = nextp; in = (in + 1) % n; signal(mutex); signal(full); //如果缺少signal(full),消费者会陷入死锁 } while(TRUE); } void consumer() { do { wait(full); wait(mutex); //如果wait(full),wait(mutex)换位置,可能出现死锁,先wait(mutex)的话,如果full = 0,empty = n此时无法获得full锁,且生产者由于无法得到mutex也无法向其中加入数据 nextc = buffer[out]; out = (out + 1) % n; signal(mutex); signal(empty);//如果缺少signal(empty),生产者会陷入死锁 } while(TRUE); } void main() { cobegin; producer(); consumer() coend; }
-
哲学家进餐问题:可能引起死锁
-
读者-写者问题
semaphore rmutex = 1, wmutex = 1; int readcount = 0; void reader() { do { wait(rmutex); //给readcount上锁 if (readcount == 0) wait(wmutex); //只要有一个Reader进程在读,便不允许Writer去写 readcount++; signal(rmutex); ... perform read operation; ... wait(rmutex); read--; if (readcount == 0) signal(wmutex); signal(rmutex); } while(TRUE); } void Writer() { do { wait(wmutex); perform write operation; signal(wmutex); }while (TRUE); } void main() { cobegin; Reader();Writer(); coend; }
进程通信
- 类型
- 共享存储器系统:共享数据结构(少量数据)、共享存储区
- 效率最高
- 管道通信系统
- 管道:只允许但向通信。需要定义两个管道
- 消息传递系统:应用最广
- 直接通信方式
- 间接通信方式(信箱)
- 客户机-服务器系统
- 共享存储器系统:共享数据结构(少量数据)、共享存储区
- 进程同步方式
- 发送进程阻塞,接收进程阻塞,用于进程之间紧密同步,进程直接无缓冲(汇合)
- 发送进程不阻塞,接收进程阻塞
- 发送进程和接收进程均不阻塞(异步)
线程的基本概念:为了提高并发性
为了减小程序在并发执行时所付出的时空开销,提高OS并发性能
- 线程和进程的比较
- 在引入线程的OS中,已把线程作为调度和分派的基本单位,进程只作为除CPU外的系统资源分配单元
- 并发性高
- 拥有资源:线程不拥有系统资源
- 独立性:比进程低
- 系统开销小
- 支持多处理机系统
- 线程状态和线程控制块
- 线程状态(无挂起,线程本身就没有什么资源)
- 执行
- 就绪
- 阻塞
- TCB类似于PCB
- 多线程OS中的进程
- 进程是一个可拥有资源的基本单位
- 多个线程可并发执行
- 进程已不是可执行实体
- 线程状态(无挂起,线程本身就没有什么资源)
线程的实现
-
内核支持线程KST
- 优点:
- 能发挥多处理机优势,同一进程中的多个线程并行执行
- 一个线程被阻塞,内核线程可以调度进程中的其他线程
- 线程切换花销小
- 可以采用多线程技术
- 缺点:同一进程的线程切换,需要从用户态转到核心态,花销大。
- 优点:
-
用户级线程ULT:
-
优点:
- 线程切换不需要转换到内核空间
- 调度算法可以是进程专用
- 用户级线程的实现与OS无关
-
缺点:
- 线程执行到系统调用的时候,不仅该线程被阻塞,进程内的所有线程也会被阻塞
- 不能发挥多处理机的优势
-
-
组合方式KST/ULT
多线程模型
-
多对一模型(用户级线程)
- 优点:线程管理在用户空间进行,效率比较高
- 缺点:一个访问内核的线程发生阻塞,则整个进程都会被阻塞
-
一对一模型(内核级线程)
的多个线程并行执行
2. 一个线程被阻塞,内核线程可以调度进程中的其他线程
3. 线程切换花销小
4. 可以采用多线程技术- 缺点:同一进程的线程切换,需要从用户态转到核心态,花销大。
-
用户级线程ULT:
-
优点:
- 线程切换不需要转换到内核空间
- 调度算法可以是进程专用
- 用户级线程的实现与OS无关
-
缺点:
- 线程执行到系统调用的时候,不仅该线程被阻塞,进程内的所有线程也会被阻塞
- 不能发挥多处理机的优势
-
-
组合方式KST/ULT
多线程模型
- 多对一模型(用户级线程)
- 优点:线程管理在用户空间进行,效率比较高
- 缺点:一个访问内核的线程发生阻塞,则整个进程都会被阻塞
- 一对一模型(内核级线程)
- 多对多模型(组合方式)