处理机管理

3/7/2024 OperatingSystem

操作系统概述

操作系统特征

  • 并发性
  • 共享性
  • 虚拟性
  • 异步性

操作系统历程:原始操作系统 ——> 管理系统 ——> 操作系统

不同操作系统

  • 批处理系统:关注吞吐量
  • 分时:关注交互性
  • 实时:关注及时响应(通过中断机制)

分时系统得特征

  • 同时性,又叫多路性
  • 独立性
  • 交互性
  • 及时性(注意和实时性区别)

微内核和宏内核:微内核的效率更低,因为需要频繁切换状态(内核态和用户态)

重定位:地址转换机构、链接装入过程

  • 静态地址重定位:在程序装入时进行地址重定位
  • 动态地址重定位:在程序执行时定位,即边执行边定位

三级调度

  • 作业调度,又叫高级调度:决定运行哪个程序,注意是程序
  • 内存调度,又叫中级调度:决定是否将进程调入内存
  • 处理机/CPU调度,又叫低级调度:决定将 CPU 分配给哪个进程

多道程序处理:利用了处理器和通道并行工作的能力

中断分类

  • 硬件中断:外部中断、终止异常

    软件中断:自陷异常、故障异常

  • 外部中断:可屏蔽中断、不可屏蔽中断

    内部中断:终止异常、自陷异常、故障异常

访管中断属于软中断/内中断,I/O 中断属于外中断

用户态、内核态的转换和逻辑地址、物理地址的转换都是由硬件完成的,中断处理也必须需要硬件参与

作业管理和用户接口

系统调用,中断

作业的调度算法

  • 先来先:FCFS
  • 短作业优先:SJF
  • 相应比高者优先:相应比 = 已等待时间 / 所需 CPU 时间

SPOOLing 系统

  • 输入输出缓存区
  • 输入输出井

进程调度

进程状态:创建、就绪、阻塞、执行、终止

  • 其中就绪、阻塞、执行是三种基本状态

进程控制块:PCB

  • 进程由 PCB、数据、以及代码三部分组成

进程是资源分配的基本单位,线程是资源调度的基本单位

进程调度算法

  • 先来先服务:FCFS
  • 最短 CPU 运行期优先:SCBF
  • 最高优先权:HPF,分为静态和动态、抢占式和非抢占式
  • 时间片轮转:RR
  • 多级反馈队列:MFQS

注意对于未明确抢占的系统,默认为非抢占式,即一个进程开始进行,将占有这个资源直到其执行结束,即使有优先级更高的进程进入就绪队列,依旧保持执行

周转时间:进程终止时间 - 进程调入时间

  • 衡量处理效率的两个重要数据:周转时间、平均周转时间

周转时间的计算:甘特图

  • 一定注意对于周转时间,后面的进程等待的时间是叠加的,叠加的除了前面进程的执行时间,还有切换进程的时间(如前面切换了3次,则周转时间要加上三次切换的时间,而不是单独计算)
  • 画出完整的甘特图再分析是最为稳妥的

线程:轻量级进程

  • 线程不共享:注册
  • 用户级线程和内核级线程:后者需要进入内核态,前者不需要

线程与进程的区别

  • 资源和地址方面
  • 调度代价方面

同步与互斥

临界区:一段互斥执行程序,程序,是程序

  • 进程处于临界区,意味着进程当前占有处理机
  • 临界区共享资源的占有和处理机的调度并不是很有关系,就是说即使进程处于临界区,仍可以被抢夺处理机(感觉是中级调度和低级调度的区别)

当 5 个进程共享一类临界资源时,共有 5 个临界区(5 个进程都有一段互斥的代码,即临界区)

任意时刻可以共享的代码(纯代码、可重入代码):就相当于 utils 包,是不可修改的代码

同步互斥的规则:空闲让进、忙则等待、有限等待、让权等待

信号量机制,P/V 操作,同步互斥设计

  • 互斥是进程间的直接约束
  • 同步是间接约束

P/V 操作是一种低级通信原语(不可分割的指令序列),是一段不可中断的过程

P/V 操作和 wait/signal 的区别

  • P(S) 操作时,要根据信号量 S 的值来确定是等待还是进入;而 S.wait() 操作直接就是让进程 S 阻塞,直到有进程唤醒他才进入就绪队列(等待和阻塞似乎不太一样)
  • V(S) 操作表示释放一个资源;signal(S) 表示令阻塞的 S 进程进入就绪状态

注意

  • 当 V(S) 时导致唤醒了等待 S 的资源,此时说明之前已经有 S < 0,即 V(S) 后仍有 S ≤ 0
  • 当执行 P(S) ,只有当 S < 0,该进程才会进入资源等待队列,一定要注意题目中是 P/V(S) 之前还是之后

进程通信

  • 共享内存:Redis
  • 消息传递:WebSocket
  • 管道传输:RabbitMQ

管程:一次只允许一个进程进入冠城

生产-消费者问题:通过一个 mutex = 1 控制缓冲区的访问权,通过 full = 0,empty = n 来控制缓冲区中资源的数量和空闲的位置

Semaphore mutex = 1, full = 0, empty = n;
void produce(){
    P(empty);
    P(mutex);
    work();
    V(mutex);
    V(full);
}

void consume(){
    P(full);
    P(mutex);
    work();
    V(mutex);
    V(empty);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

在有多个生产、消费者时,或有生产消费链时,要使用多个 mutex 去控制每一个缓冲区的访问权,多个 full 和 empty 去控制缓冲区的资源存储情况

读写互斥问题:通过 count = 0 来记录当前读者数量,通过 rw 来控制读写权限,通过 mutex 来控制操作 count 的权限

  • 必须用 mutex 给 count 的操作(+1/-1)上锁,不然多个读者同时访问时将出现脏读

基本的读者进程

read(){
    // 要读了,要修改 count++ 了,事先要拿 count 的访问权
    P(mutex);
    if(count == 0){ // 当为第一个读者,要等待读写权限
        P(rw)
    }
    count++;
    V(mutex)
    reading();
    // 读完了,要修改 count-- 了,事先拿 count 访问权
    P(mutex);
    count--;
    if(count == 0){
        V(rw) // 当没有读者,释放读写权限
    }
    V(mutex)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

基本写者进程,就是这么简单

write(){
    P(rw);
    writting();
    V(rw);
}
1
2
3
4
5

这有很多变式,如单向路口,同时仅限一方通行:此时需要设置两个 count 去记录两批读者的数量,两个 mutex 来给两个 count 上锁,用一个 pass 信号量给“通行”这一操作上锁(即一方通行时,另一方被 pass 锁上)

哲学家进食问题(一个圆桌):通过一组信号量控制哲学家拿筷子的操作,为了避免哲学家同时拿左手筷子导致死锁,采用给哲学家拿左右两只筷子(两个连续操作)上锁的方式

Semagore stick[1,1,1,1,1];
Semagore mutex = 1; // 给拿两只筷子操作上锁
void eat(int i){ // 第 i 个哲学家进食
    P(mutex);
    P(stick[i] && stick[(i+1)%5]);
    eatting;
    V(stick[i] && stick[(i+1)%5]);
    V(mutex);
}
1
2
3
4
5
6
7
8
9

这样每次保证只有一个哲学家进食,不可能出现有其他哲学家抢他筷子的情况发生(会导致忙等,但不失为一种同步互斥方案)

注意:在写题时,一定要写 main 函数,若有需要,应将主要功能用 while(1) 包含起来持续运行

死锁

当有 n 个进程时,就绪队列最多有 n-1 个进程,而阻塞队列最多有 n 个进程

  • 当发生死锁时,n 个进程全被阻塞

死锁预防:破坏死锁产生的必要条件

  • 破坏互斥条件:SPOOLing
  • 破坏不可剥夺条件:抢夺式分配
  • 破坏保持请求条件:一次性分配
  • 破坏循环等待条件:给资源编号

死锁避免:银行家算法

  • 系统处于不安全状态可能发生死锁:因为可以主动撤销资源,不是说不安全就一定要继续进行下去直到发展成死锁

死锁检测:资源分配图,矩形中的圆圈表示资源,圆圈表示进程,箭头朝进程表示分配,朝资源表示请求分配,通过撤销进程来判断资源是否足够分配(若撤销了还不够,说明产生死锁)

死锁解除

  • 撤销所有陷入死锁的进程:一刀切
  • 逐个撤销陷入死锁中的进程:逐个抓
  • 使陷入死锁中的进程逐个放弃所占有资源,直到死锁消失:注意此时并不撤销进程,只是令其放弃资源,转入阻塞队列
Last Updated: 9/13/2024, 1:34:55 AM
妖风过海
刘森