diff --git a/CS302-OS-Notes.html b/CS302-OS-Notes.html index 59877c1..14bbced 100644 --- a/CS302-OS-Notes.html +++ b/CS302-OS-Notes.html @@ -510,8 +510,8 @@
南方科技大学 计算机科学与工程系 11812804 董正
操作系统 Operating System前言 Preface第三章 进程 Process3.1 基本概念3.1.1 进程的概念3.1.2 进程的状态 Process States3.1.3 进程控制块 Process Control Block3.2 进程生命周期3.2.1 进程标识符 Process Identifier3.2.2 进程创建 Process Creation3.2.3 进程执行 Process Execution3.2.4 进程等待3.2.5 进程时间3.2.6 进程终止 Process Termination3.2.7 进程生命周期 Process Lifecycle第四章 线程 Thread4.1 线程的概念4.2 线程的组成4.3 线程和进程的区别4.4 线程的生命周期 Thread Lifecycle4.5 多线程进程 Multithreaded Process4.6 多线程调度4.7 Multiprocessing, Multithreading and Multiprogramming第五章 进程调度 Process Scheduling5.1 基本概念5.1.1 上下文切换 Context Switch5.1.2 调度队列5.1.3 调度程序 Scheduler5.1.4 Dispatcher5.2 调度准则5.3 调度算法 Scheduling Algorithm5.3.1 先到先服务调度 First-Come-First-Served (FCFS)5.3.2 最短作业优先调度 Shortest-Job-First (SJF)5.3.2.1 非抢占 (Non-Preemptive) SJF5.3.2.2 抢占 SJF5.3.3 轮转调度 Round Robin (RR)5.3.4 优先级调度 Priority Scheduling5.3.4.1 Multiple Queue Priority Scheduling第六章 同步 Synchronization6.1 进程间通信 Inter-Process Communication (IPC)6.2 临界区 Critical Section6.2.1 竞争条件 Race Condition6.2.2 临界区问题 Critical Section Problem6.2.3 临界区问题的要求6.3 临界区问题的解决方案 Solutions for Critical Section Problem6.3.1 硬件同步 (×) Hardware Synchronization6.3.2 基本自旋锁 (×) Basic Spin Lock6.3.3 Peterson's Solution6.3.4 信号量 Semaphore6.4 经典同步问题6.4.1 有界缓冲问题 Bounded-Buffer Problem6.4.2 读者-作者问题 Reader-Writer Problem6.4.3 哲学家就餐问题 Dining-Philosophers Problem第七章 死锁 Deadlock7.1 死锁的概念7.2 死锁的特征7.2.1 死锁的必要条件7.2.2 资源分配图 Resource-Allocation Graph7.3 死锁的处理方法7.4 死锁检测 Deadlock Detection7.4.1 死锁检测算法7.4.2 死锁恢复7.5 死锁预防 Deadlock Prevention7.6 死锁避免 Deadlock Avoidance7.6.1 安全状态7.6.2 资源分配图算法7.6.3 银行家算法 Banker's Algorithm第八章 内存管理策略8.1 背景8.1.1 Aspects of Memory Multiplexing8.1.2 地址绑定 Address Binding8.1.3 逻辑地址空间与物理地址空间8.1.4 动态加载 Dynamic Loading8.1.5 动态链接与共享库8.2 交换 Swap8.3 连续内存分配 Contiguous Memory Allocation8.3.1 Uniprogramming8.3.2 内存保护 Protection8.3.3 多分区方法 Multiple-Partition Method8.3.3 碎片 Fragmentation8.4 分段 Segmentation8.5 分页 Paging8.5.1 页表 Page Table8.5.2 共享页8.5.3 分层分页 Multilevel Paging8.5.4 分段+分页第九章 虚拟内存管理9.1 缓存 Cache9.2 转换表缓冲区 Transition Look-aside Buffer (TLB)9.3 请求调页 Demand Paging9.3.1 基本概念9.3.2 请求调页的性能9.4 页面置换 Page Replacement9.4.1 Cache Miss 的分类9.4.2 FIFO 页面置换9.4.3 最优页面置换 MIN9.4.4 LRU 页面置换9.4.5 近似 LRU 页面置换9.4.5.1 时钟算法 Clock Algorithm9.4.5.2 Second Chance List Algorithm9.5 帧分配 Frame Allocation9.5.1 全局分配与局部分配9.5.2 分配算法第十 & 十一章 文件系统 File System10.1 文件系统概念10.2 文件和目录 Files and Directories10.2.1 目录的组成10.2.2 文件10.3 磁盘管理策略10.4 目录分配10.4.1 连续分配 Contiguous Allocation10.4.2 链接分配 Linked Allocation10.4.3 索引分配 Index Allocation10.5 文件分配表 FAT10.5.1 FAT 的原理10.5.2 FAT 文件系统的大小10.5.3 FAT 文件系统结构10.5.4 FAT 文件遍历10.5.5 FAT Directory Entry10.5.6 FAT 读文件10.5.7 FAT 写文件10.5.8 FAT 删除文件10.5.9 总结10.6 iNode10.6.1 iNode 的原理10.6.2 iNode 的结构10.6.3 iNode 文件大小10.7 可扩展文件系统 Ext10.7.1 Ext 文件系统的大小10.7.2 Ext 文件系统结构10.7.3 Ext 的 iNode 结构10.7.4 Ext 删除文件10.7.5 硬链接 Hard Link10.7.6 符号链接 (软链接) Symbolic (Soft) Link10.8 NTFS10.8.1 NTFS 文件系统结构10.8.2 NTFS 文件存储10.9 内存映射文件 Memory Mapped File10.10 文件系统总结第十二章 大容量存储结构12.1 大容量存储结构概述12.1.1 磁盘 Magnetic Disk (Hard Disk)12.1.2 磁盘性能12.1.2 固态磁盘 Solid State Disk (SSD)12.2 磁盘调度 Disk Scheduling12.2.1 FCFS 调度12.2.2 SSTF 调度12.2.3 SCAN 调度12.2.4 C-SCAN 调度12.2.5 LOOK 与 C-LOOK 调度12.2.6 调度算法的选择第十三章 I/O 系统13.1 I/O 硬件13.2 CPU 访问 I/O 设备13.3 控制器与 I/O 设备的数据传输13.4 I/O 设备与 CPU 通信13.4.1 轮询 Polling13.4.2 I/O 中断 I/O Interrupt13.5 I/O 请求生命周期13.6 I/O 性能END
笔记结构基于《操作系统概念(第九版)》
Based on Operating System Concepts Ninth Edition
CPU 活动
进程 (Process) 是执行的程序
Process is a program in execution
进程还包括:
程序 (Program) 和进程
状态 | 英文 | 说明 |
---|---|---|
新的 | new | 进程正在创建 |
运行 | running | 指令正在执行 |
等待 | waiting/blocked | 进程等待发生某个事件,如 IO 完成或收到信号 |
就绪 | ready | 进程等待分配处理器 |
终止 | terminated | 进程已经完成执行 |
等待状态又分为
刚 fork 的进程都会变成 ready 状态
进程控制块 PCB (任务控制块 Task Control Block)
在内存 (Main Memory) 里
PCB 是系统感知进程存在的唯一标志
进程状态 Process State
程序计数器 PC
CPU 寄存器 CPU Register
CPU 调度信息 CPU-scheduling Infomation
进程优先级,调度队列的指针和其他调度参数
内存管理信息 Memory-management Infomation
基地址,界限寄存器的值,页表或段表等
记账信息 Accounting Infomation
CPU 时间,实际使用时间,时间期限,记账数据,作业或进程数量等
IO 状态信息 IO Status Infomation
分配给进程的 IO 设备列表,打开文件列表等
几个概念
task_struct
in Linux进程标识符 Process Identifier (PID)
系统的每个进程都有一个唯一的整数 PID
System call getpid()
: return the PID of the calling process
init
进程
PID = 1, 所有用户进程的父进程或根进程
代码位于 /sbin /init
它的第一个任务是创建进程 fork()+exec*()
System call fork()
: creates a new process by duplicating the calling process.
fork 出的子进程从 fork 调用的下一行开始执行(因为 PC 也复制了)
在代码中如何区分父进程和子进程
pid=fork()
, 则父进程中 pid
变量等于子进程的 PID,子进程中 pid=0
1if (!pid) {
2 // 只有子进程执行
3}
4else {
5 // 只有父进程执行
6}
父进程和子进程执行顺序不确定
fork
的流程, 内核空间的动作
复制 PCB
更新 PCB 和 task list
复制用户空间
return
System call exec*()
Example: ls -l
args[0]
是程序的名字
The process is changing the code that is executing and never returns to the original code.
exec*()
之后的代码不会执行了,因为调用之后该进程就去执行 exec
指定的程序了
User space 的信息被覆盖
Program Code
Memory
Register Value: 如 PC
Kernel space 的信息保留: PID, 进程关系等
exec*()
的内核执行过程
System call wait()
Suspend the calling process to waiting state and return (wakes up) when
Return immediately (i.e., does nothing) if
给子进程收尸 见 3.2.6
fork()+exec*()+wait()=system()
例: shell 里输入命令 -> 执行相应程序 -> 程序终止 -> 返回 shell
init
, 所有的进程都是 fork()+exec*()
来的实际时间 Real Time
Wall-clock time
用户时间 User Time
CPU 在用户空间花费的时间
系统时间 System Time
CPU 在内核空间花费的时间
User Time + Sys Time 决定了程序的性能 (Performance)
System call exit()
: terminate the calling process
exit()
的执行过程
Clean up most of the allocated kernel space memory
Clean up the exit process's user space memory
Notify the parent with SIGCHLD.
僵尸进程 Zombie Process
wait()
wait()
,这样的进程称为僵尸进程wait()
,僵尸进程的进程标识符和它在进程表中的条目就会释放子进程先终止,父进程再调用 wait()
也可以,SIGCHLD 不会消失,但是这段间隔内僵尸进程就一直存在、占用资源
Linux 系统中僵尸进程被标为 <defunct>
查看: ps aux | grep <defunct>
exit()
system call turns a process into a zombie when
The process calls exit()
The process returns from main()
The process terminates abnormally
这种情况下 kernel 会帮忙给他调用 exit()
The fork bomb
PID 是有限的,Linux 中 PID 最大值为 32768
cat / proc /sys/ pid_max
fork bomb (僵尸大军)
xxxxxxxxxx
41int main() {
2 while (fork());
3 return 0;
4}
孤儿进程 Orphan Process
wait()
就终止,子进程变成孤儿进程init
进程作为孤儿进程的父进程 (Re-parent)exit()
里完成,见下图init
进程定期调用 wait()
以便收集任何孤儿进程的退出状态,并释放孤儿进程标识符和进程表条目
forked
Ready
Running
Blocked
Interruptable waiting
Un-interruptable waiting
计网的程序里经常碰见,纯贵物,谁设计的抓紧埋了吧
Return back to ready
Terminated
Heavyweight Process
A process has a single thread of control
线程 Thread
A sequential execution stream within process
又称 Lightweight Process
多线程 Multithreading
A single program made up of a number of different concurrent (并发) activities
结构图
State shared by all threads in process/address space
State "private" to each thread
栈
Process | Thread |
---|---|
Process means any program is in execution. | Thread means segment of a process. |
Process takes more time to terminate. | Thread takes less time to terminate. |
It takes more time for creation. | It takes less time for creation. |
It also takes more time for context switching. | It takes less time for context switching. |
Process is less efficient in term of communication. | Thread is more efficient in term of communication. |
Process consume more resources. | Thread consume less resources. |
Process is isolated. | Threads share memory. |
Process is called heavy weight process. | Thread is called light weight process. |
Process switching uses interface in operating system. | Thread switching does not require to call a operating system and cause an interrupt to the kernel. |
If one process is blocked then it will not effect the execution of other process | Second thread in the same task couldnot run, while one server thread is blocked. |
Process has its own Process Control Block, Stack and Address Space. | Thread has Parents' PCB, its own Thread Control Block and Stack and common Address space. |
PCB 指向多个 TCB
Switching threads within a block is a simple thread switch
Switching threads across blocks requires changes to memory and I/O address tables
超线程 Hyper-Threading
超线程(hyper-threading)其实就是同时多线程(simultaneous multi-theading), 是一项允许一个CPU执行多个控制流的技术。它的原理很简单,就是把一颗CPU当成两颗来用,将一颗具有超线程功能的物理CPU变成两颗逻辑CPU,而逻辑CPU对操作系统来说,跟物理CPU并没有什么区别。因此,操作系统会把工作线程分派给这两颗(逻辑)CPU上去执行,让(多个或单个)应用程序的多个线程,能够同时在同一颗CPU上被执行。注意:两颗逻辑CPU共享单颗物理CPU的所有执行资源。因此,我们可以认为,超线程技术就是对CPU的虚拟化
多进程 Multiprocessing
Multiple CPUs
A computer using more than one CPU at a time.
多线程 Multithreading
Multiple threads per Process
多道程序设计 Multiprogramming
Multiple Jobs or Processes
A computer running more than one program at a time
切换 CPU 到另一个进程需要保存当前进程状态和恢复另一个进程的状态,这个任务称为上下文切换
当进行上下文切换时,内核会将旧进程的状态保存在其 PCB 中,然后加载经调度而要执行的新进程的上下文
上下文切换是纯粹的时间开销 (Overhead),因为 CPU 在此期间没有做任何有用工作
上下文切换非常耗时
什么时候 Context Switch
wait(), sleep()
等作业队列 Job Queue
包含所有进程
就绪队列 Ready Queue
等待运行的进程
PCB 构成的链表
设备队列 Device Queue
等待使用该 IO 设备的进程队列
每个设备都有
队列图 Queueing Diagram
圆圈代表服务队列的资源, 箭头代表系统内的进程流向
↓执行或分派 (Dispatch)
缓冲池
通常来说,对于批处理系统,提交的进程多于可执行的,这些进程被保存到大容量存储设备(如磁盘)的缓冲池,以便以后执行
调度程序 (调度器)
调度器 | 别名 | 作用 |
---|---|---|
长期调度程序 Long-term Scheduler | 作业调度程序 Job Scheduler | 从缓冲池中选择进程加载到内存 |
短期调度程序 Short-term Scheduler | CPU 调度程序 | 从 Ready Queue 中选择进程并分配 CPU |
中期调度程序 Medium-term Scheduler | 进程交换 |
进程分类
中文 | 英文 | 特点 |
---|---|---|
I/O 密集型进程 | I/O Bounded Process | 执行 I/O 比执行计算耗时 |
CPU 密集型进程 | CPU Bounded Process | 很少I/O, 执行计算用时长 |
长期调度程序需要选择这两种进程的合理组合才能最大化 CPU 和 IO 设备的利用
Dispatcher 是一个模块,用来将 CPU 控制交给由 CPU 调度程序选择的进程
功能
调度延迟 Dispatch Latency
Dispatcher 停止一个进程而启动另一个进程所需的时间
Dispatcher 和 Scheduler 的区别
中文书把 dispatcher 也翻译成调度程序,我真想一拳干碎你的眼镜
https://www.differencebetween.com/difference-between-scheduler-and-vs-dispatcher
https://www.geeksforgeeks.org/difference-between-dispatcher-and-scheduler
The key difference between scheduler and dispatcher is that the scheduler selects a process out of several processes to be executed while the dispatcher allocates the CPU for the selected process by the scheduler.
Properties | DISPATCHER | SCHEDULER |
---|---|---|
Definition | Dispatcher is a module that gives control of CPU to the process selected by short term scheduler | Scheduler is something which selects a process among various processes |
Types | There are no different types in dispatcher. It is just a code segment. | There are 3 types of scheduler i.e. Long-term, Short-term, Medium-term |
Dependency | Working of dispatcher is dependent on scheduler. Means dispatcher have to wait until scheduler selects a process. | Scheduler works independently. It works immediately when needed |
Algorithm | Dispatcher has no specific algorithm for its implementation | Scheduler works on various algorithm such as FCFS, SJF, RR etc. |
Time Taken | The time taken by dispatcher is called dispatch latency. | Time taken by scheduler is usually negligible. Hence we neglect it. |
Functions | Dispatcher is also responsible for: Context Switching, Switch to user mode, Jumping to proper location when process again restarted | The only work of scheduler is selection of processes. |
CPU 使用率
应该使 CPU 尽可能忙碌
吞吐量
一个时间单元内进程完成的数量
周转时间
从进程提交到完成的时间段称为周转时间 (Turnaround Time)
等待时间
在就绪队列中等待所花时间之和
响应时间
从提交请求到产生第一响应的时间
Number of Context Switches (from 课件)
尽可能少做上下文切换
字面意思
每个进程都有一个时间量 (Time Quantum) 或时间片 (Time Slice)
通常 10~100ms
当时间片用完时,该进程就会释放 CPU (相当于抢占)
调度程序选择下一个时间片 > 0 的进程
如果所有进程都用完了时间片,它们的时间片同时被 recharge 到初始值
就绪队列为循环队列,进程被依次执行
每个进程都有一个优先级
调度程序根据优先级选择进程
优先队列
分类
新进程到来时,重新 schedule (这里会发生抢占)
如果当前进程被抢占,它先出队再入队
Linux Scheduler
匿名管道 Pipe
信号 Signal
例: ls | less
IPC Models
User space 里的所有东西都不能 share,所以 pipe 之类的都在 kernel 里
临界区 Critical Section
每个进程有一段代码,进程在执行该段代码时可能修改公共变量、更新一个表、写一个文件等
进入区 Entry Section
进入临界区前,请求许可的代码段
退出区 Exit Section
剩余区 Remainder Section
互斥 Mutual Exclusion
如果一个进程在其临界区内执行,那么其他进程都不能在临界区内执行
进步 Progress
如果没有进程在临界区内执行,并且有进程需要进入临界区,那么只有那些不在剩余区内的进程可以参加选择,以便确定谁下次进入临界区,而且这种选择不能无限推迟
别让执行临界区的进程空着,除非大家都不想进临界区
有限等待 Bounded Waiting
从一个进程做出进入临界区的请求直到这个请求允许为止,其他进程允许进入其临界区的次数有上限
别让一个进程等一辈子
Lock-based
Spin-based Lock
Sleep-based Lock
pthread_mutex_lock
Lock-free
单核
正确,但是不能接受
如果有个进程在 CS 里写个死循环就全卡这了
多核
不正确,除非把所有核的中断全都禁止
原理
设置一个公共变量 turn
来决定哪个进程可以进 CS
太浪费 CPU
违反 Progress
多个进程一定是交替执行
如果一个进程不打算进 CS 但是另一个进程交出了权限,那就要等很长时间 (no progress)
Example: 这种情况下没人在 CS 里。不能让执行 CS 的进程空着
在 turn
的基础上新加一个布尔数组 interested
If I don't show interest
I let you all go
If we both show interest
Take turns
x1int turn;
2int interested[2] = {false, false};
3
4void lock(int process) {
5 int other = 1 - process;
6 interested[process] = true;
7 turn = other;
8 while (turn == other && interested[other]); // busy waiting
9}
10
11void unlock(int process) {
12 interested[process] = false;
13}
会产生优先级翻转问题 (Priority Invasion)
优先级
为什么 turn=other
不是 turn=process
我们假设是这样
xxxxxxxxxx
21turn=自己;
2while (turn==自己 && interested[别人]);
如果现在有三个进程
我们脸比较黑,这三个进程经过调度,都该执行 turn=自己
这一行
那么最终 turn
是几,就取决于调度器了
假设调度器就是按 的顺序调度的,那么最后 turn=3
现在我们检查 while
的条件
turn=3
, 前半句不成立, 不需要 waitturn=3
, 前半句不成立, 不需要 wait那么现在 都被许可进入 CS,违反了互斥原则
正确是这样:
xxxxxxxxxx
41turn=别人;
2while (turn==别人们 && interested[别人们]);
3// while ((turn==x && interested[x]) || (turn==y && interested[y]))
4// while (turn!=自己 && interested[别人们])
还是这个例子,我们假设 turn
的赋值是 1 给 2,2 给 3,3 给 1
turn=别人
这一行,还是按 123 的顺序调度的turn=1
while
的条件,只有 可以进 CS信号量是一个 Structure
int
,表示剩余多少资源可用xxxxxxxxxx
41typedef struct {
2 int value;
3 struct process *list;
4} semaphore;
Wait (P 操作)
xxxxxxxxxx
71wait(semaphore *s) {
2 s->value--;
3 if (s->value<0) {
4 add this process to s->list;
5 block();
6 }
7}
Post (V 操作)
xxxxxxxxxx
71post(semaphore *s) {
2 s->value++;
3 if (s->value<=0){
4 remove a process p from s->list;
5 wakeup(p);
6 }
7}
分类
二进制信号量 Binary Semaphore
只能 0 或 1
计数信号量 Counting Semaphore
可以 > 1
又称生产者-消费者问题 (Producer-Consumer Problem)
组成
Bounded Buffer
Producer Process
Consumer Process
要求
Producer
Consumer
例子
Semaphore 实现
xxxxxxxxxx
331semaphore mutex=1;
2semaphore avail=N;
3semaphore fill=0;
4
5void producer() {
6 int item;
7
8 while (true) {
9 item=produce_item();
10
11 wait(&avail);
12 wait(&mutex);
13
14 insert_item(item);
15
16 post(&mutex);
17 post(&fill);
18 }
19}
20
21void consumer() {
22 int item;
23
24 while (true){
25 wait(&fill);
26 wait(&mutex);
27
28 item=remove_item();
29
30 post(&mutex);
31 post(&avail);
32 }
33}
要求
问题描述
每个哲学家有两个可能的动作
如果一个哲学家要吃面条,他必须同时获得左右两根筷子
拿起来的筷子不会被别人抢
要求
设计一个 Protocol,保证所有哲学家
解决方案设计
在正常操作模式下,进程只能按如下顺序使用资源:
申请
进程请求资源。如果进程不能立即被允许,那么它应该等待,直到获取该资源
使用
进程对资源进行操作
释放
进程释放资源
死锁 Deadlock
Deadlock is a situation where a set of processes are blocked because each process is holding a resource and waiting for another resource acquired by some other process.
饥饿 Starvation
Indefinite Blocking
A condition in which a process is indefinitely delayed because other processes are always given preference.
Starvation is the problem that occurs when high priority processes keep executing and low priority processes get blocked for indefinite time.
Deadlock 一定会造成 starvation
互斥 Mutual Exclusion
Only one thread at a time can use a resource.
占有并等待 Hold and Wait
一个进程应占有至少一个资源并等待另一个资源,而该资源为其他进程所占有
非抢占 No Preemption
资源不能被抢占,即资源只能被进程在完成任务后自愿释放
循环等待 Circular Wait
有一组等待进程
注意是必要条件,即使这些条件都满足也不一定死锁,还需要运气比较背
圆表示进程
矩形表示资源
矩形内的点表示资源实例
申请边 Request Edge
进程指向资源的边
分配边 Assignment Edge
资源指向进程的边
如果分配图没有环,那么系统一定没有死锁;如果有环,那么可能存在死锁
死锁的例子
有环没死锁的例子
让 先执行完
通过协议来预防或避免死锁,确保系统不会进入死锁状态
允许系统进入死锁状态,然后检测并恢复
忽视,认为死锁不可能在系统内发生
这种方案被 Linux, Windows 等大多数 OS 采用
就算出现了死锁,OS 也不管
[xxx] 表示数组
xxxxxxxxxx
131[Avail] = [FreeResources]
2Add all nodes to UNFINISHED
3
4do {
5done = true
6Foreach node in UNFINISHED {
7if ([Request_node] <= [Avail]) {
8remove node from UNFINISHED
9[Avail] = [Avail] + [Alloc_node]
10done = false
11}
12}
13} until(done)
当检测到死锁后:
进程终止
Terminate thread, force it to give up resources
资源抢占
Preempt resources without killing off process
回滚
Roll back actions of deadlocked threads
Many operating systems use other options
核心:打破四个必要条件
互斥
持有且等待
无抢占
如果一个进程持有资源并申请一个不能被立即分配的资源,那么它现在分配的资源都可以被抢占
相当于把它现有的资源都释放了
循环等待
需求边 Claim Edge
进程指向资源,虚线
进程 可能在将来申请某个资源
只有在将申请边变成分配边 (反向实线箭头) 并且不会导致资源分配图形成环时,才能允许申请
时间复杂度
, 为进程数量
个进程, 种资源
xxxxxxxxxx
121Add all nodes to UNFINISHED
2
3do {
4done = true
5Foreach node in UNFINISHED {
6if ([Max_node] - [Alloc_node] <= [Avail]) {
7remove node from UNFINISHED
8[Avail] = [Avail] + [Alloc_node]
9done = false
10}
11}
12} until(done)
例: 可以按 0213 或 0231 的顺序执行完
现在有个新的 ,比如
检查
检查
假设把资源分配给
一个内存,多个进程,怎么管理
Protection
Prevent access to private memory of other processes
Controlled Overlap
Sometimes we want to share memory across processes
Translation
Ability to translate accesses from one address space (virtual) to a different one (physical)
源程序中的地址通常是用符号表示 (如变量 count
)。编译器通常将这些符号地址绑定 (bind) 到可重定位的地址 (如“从本模块开始的第 14 字节”)。链接程序或加载程序再将这些可重定位的地址绑定到绝对地址 (如 74014)。每次绑定都是一个从一个地址空间到另一个地址空间的映射。
通常,指令和数据绑定到存储器地址可以在任何一步进行:
编译时 Compile Time
如果在编译时就已经知道进程将在内存中的驻留地址,那么就可以生成绝对代码 (Absolute Code)
例: MS-DOS 的 .COM 格式程序
加载时 Load Time
如果在编译时并不知道进程将驻留在何处,那么编译器就应生成可重定位代码 (Relocatable Code)。对这种情况,最后绑定会延迟到加载时进行
执行时 Runtime time
如果进程在执行时可以从一个内存段移到另一个内存段,那么绑定应延迟到执行时才进行
大多数通用 OS 采用
逻辑地址 Logical Address = 虚拟地址 Virtual Address
CPU 生成的地址
物理地址 Physical Address
真正的内存地址,加载到内存地址寄存器 (Memory-Address Register) 的地址
编译时和加载时的地址绑定会生成相同的逻辑地址和物理地址
执行时的绑定生成不同的逻辑地址和物理地址
内存管理单元 MMU
从虚拟地址到物理地址的运行时映射是由内存管理单元 (Memory Management Unit) 的硬件设备来完成 (包括查页表之类的都是 MMU 干的)
大多数 on-chip
动态链接的概念与动态加载相似。只是这里不是将加载延迟到运行时,而是将链接延迟到运行时。这一特点通常用于系统库,如语言子程序库。没有这一点,系统上的所有程序都需要一份语言库的副本,这一需求浪费了磁盘空间和内存空间。
存根 Stub
如果有动态链接,二进制镜像中每个库程序的应用都有一个存根(stub)。存根是一小段代码,用以指出如何定位适当的内存驻留的库程序,或如果该程序不在内存中应如何安装入库。不管怎样,存根会用子程序地址来代替自己,并开始执行子程序。因此,下次再执行该子程序代码时,就可以直接进行,而不会因动态链接产生任何开销。采用这种方案,使用语言库的所有进程只需要一个库代码副本就可以了。
举例来说,你在程序里调用了 STL 里的 Map,如果没有动态链接,就相当于你把 STL 里 Map 的源文件复制一份到了你的项目里。在动态链接下,不管多少程序调用,都只会调用那一份代码。
动态连接也可用于库更新。一个库可以被新的版本所替代,且使用该库的所有程序会自动使用新的版本。没有动态链接,所有这些程序必须重新链接以便访问。
Refer to 进程调度 5.1.3 中期调度程序
进程需要在内存中以便执行。进程也可以暂时从内存中交换 (swap) 到备份存储 (backing store,一般是磁盘) 上,当需要再次执行时在调回到内存中。
将内存分为多个分区,每个分区分给一个进程
固定分区 Fixed-size Partition
Each process has same memory size
可变分区 Variable Partition
动态存储分配问题 Dynamic Storage-Alloction Problem
当新进程需要内存时,系统为该进程查找足够大的孔
如果孔太大,那么就分为两块
进程终止时,释放内存,该内存合并回孔的集合
如果新孔与其他孔相邻,则合并成大孔
系统检查是否有等待内存空间的进程,以及新合并的孔能否满足等待进程等
从可用孔中选择一个分配的常用方法
首次适应 First-fit
分配首个足够大的孔
最优适应 Best-fit
分配最小的足够大的孔
最差适应 Worst-fit
分配最大的足够大的孔
内碎片 Internal Fragmentation
分配给进程的内存比所需的大,多余的那一部分就是内碎片
外碎片 External Fragmentation
两个进程之间的空闲孔,而且这个孔太小,没法分配给别的进程
紧缩 Compaction
移动已分配的内存,使得所有外碎片合并成一大块
只有在运行时绑定才可以使用紧缩,因为要重写基地址寄存器和界限寄存器
逻辑地址空间由一组段构成,每个段有名称和长度
地址指定了段名称和段内偏移 (Offset)
逻辑地址由有序对组成 <段号,偏移>
段表 Segment Table
在 CPU 里
段表的每个条目包含:
图上没有 Check Valid 的内容
例 1:
例 2:
不多说,全是计组学过的内容
注意第一条指令 load address 取的是虚拟地址 0x4050, 物理地址只有真正访问内存的时候才翻译过去
分段的特点
Virtual address space has holes
When it is OK to address outside valid range?
Need protection mode in segment table
Fragmentation
What must be saved/restored on context switch?
每个逻辑地址分为两部分
与分段对比
页表条目
在内存里
分页可以消除外碎片
一页的大小需要 trade off
What needs to be switched on a context switch? -Page table pointer and limit
Core Map
Do we need a reverse mapping (i.e. physical page -> virtual page)?
注意这里,比如 level 1 offset 10 位,那么二级页表最多可能有 个
当然大部分情况都是 < 1024 的,这就是多级页表的作用,解决了之前单个页表里一大堆 null 没用还占地方的问题
Tree of tables
What must be saved/restored on context switch?
共享
Cache
A repository for copies that can be accessed more quickly than the original
平均访问时间 Average Access time
注意这里跟计组学的不一样,访问 cache 然后没找到的时间没算进去
计组:
时间局部性 Temporal Locality
If you used some data recently, you will likely use it again
Keep recently accessed data items closer to processor
空间局部性 Spatial Locality
If you used some data recently, you will likely access its neighbors
Move contiguous blocks to the upper levels
其他内容详见计组课件
Cache 的应用
Page Table Entry (PTE) 的 cache
在 CPU 里
TLB Miss 的处理 (以下来自计组课件 永远滴神)
If page is in memory
Load the PTE from memory and retry
Could be handled in hardware
Or in software
If page is not in memory (page fault)
TLB 也可以多级 (L1, L2, ...)
TLB + Cache
Does software loaded TLB need use bit?
定义
Keep all pages of the frames in the secondary memory (外存) until they are required.
A page is delivered into the memory on demand i.e., only when a reference is made to a location on that page.
为什么要请求调页
内存相当于外存的 cache
缺页错误 Page Fault
对标记为无效 (valid bit) 的页面访问
缺页错误的处理
概括
具体
陷入操作系统 (trap)
保存寄存器和进程状态
确定中断是否为缺页错误
检查页面是否合法,并确定页面的磁盘位置
从磁盘读入页面到空闲帧
在等待时,将 CPU 分配给其他用户
收到来自 IO 子系统的中断 (IO 完成)
保存其他用户的寄存器和进程状态
确认中断是来自上述磁盘的
修正页表和其他表,以表示所需页面现在已在内存中
等待 CPU 再次分配给本进程
恢复用户寄存器、进程状态和新页表,再重新执行中断的指令
课件
D=1
), write contents back to diskOS 如何拿到一个空闲帧
Keeps a free list
Unix runs a "reaper" if memory gets too full
As a last resort, evict a dirty page first
有效访问时间 Effective Access Time
: 缺页错误率 Page Fault Rate
: 内存访问时间
注意这里课件和书上不一样,书上是 ,一个破公式就不能统一一下??
Compulsory Miss (Cold Start Miss)
Pages that have never been paged into memory before
How might we remove these misses?
Capacity Miss
Not enough memory. Must somehow increase available memory size
Conflict Miss
Policy Miss
Throw out oldest page. Be fair let every page live in memory for sameamount of time.
Bad: may throw out heavily used pages instead of infrequently used
理论实现:队列
xxxxxxxxxx
261class FIFOCache : public Cache {
2 private:
3 list<int> lst;
4
5 public:
6 FIFOCache(int size) : Cache(size) {}
7
8 bool full() override {
9 return lst.size()==this->size;
10 }
11
12 bool contains(int x) override {
13 return find(lst.begin(), lst.end(), x)!=lst.end();
14 }
15
16 void insert(int x) override {
17 if (this->contains(x)) {
18 this->hitCount++;
19 }
20 else {
21 if (this->full())
22 lst.pop_front();
23 lst.push_back(x);
24 }
25 }
26};
例: 3 个 frame,4 个 page,访问顺序: A B C A B D A D B C B
Page Fault: 7
Bélády 异常 (Bélády's Anomaly)
对于 FIFO 策略,Mem size 增大,page fault 有可能反而变多
置换最长时间不会使用的页面 (farthest-in-the-future)
Offline 算法,需要提前知道访问序列
理论天花板,实际不可能
理论实现: 好多实现方式
xxxxxxxxxx
571class MINCache : public Cache {
2 private:
3 set<int> s;
4 priority_queue<pair<int, int>> pq; // <index, pagenumber>
5
6 vector<int> pages;
7 vector<int> nxt;
8
9 public:
10 MINCache(int size) : Cache(size) {}
11
12 bool full() override {
13 return s.size()==this->size;
14 }
15
16 bool contains(int x) override {
17 return s.find(x)!=s.end();
18 }
19
20 void init(int n) {
21 int pageNum;
22 for (int i=0;i<n;i++) {
23 cin>>pageNum;
24 pages.push_back(pageNum);
25 nxt.push_back(INT_MAX);
26 }
27
28 map<int, int> temp;
29 for (int i=n-1;i>=0;i--) {
30 map<int, int>::iterator p=temp.find(pages[i]);
31 if (p!=temp.end())
32 nxt[i]=p->second;
33 temp[pages[i]]=i;
34 }
35 }
36
37 void insert(int i) override {
38 if (this->contains(pages[i]))
39 this->hitCount++;
40 else {
41 if (this->full()) {
42 auto t=pq.top();
43 pq.pop();
44 s.erase(t.second);
45 }
46
47 s.insert(pages[i]);
48 }
49
50 pq.push(make_pair(nxt[i], pages[i]));
51 }
52
53 void start() {
54 for (int i=0;i<pages.size();i++)
55 this->insert(i);
56 }
57};
例:A B C A B D A D B C B
Page Fault: 5
最近最少使用 Least Recently Used
Replace page that has not been used for the longest time
理论实现:双向链表
xxxxxxxxxx
341class LRUCache : public Cache {
2 private:
3 list<int> lst;
4
5 public:
6 LRUCache(int size) : Cache(size) {}
7
8 bool full() override {
9 return lst.size()==this->size;
10 }
11
12 list<int>::iterator findElement(int x) {
13 return find(lst.begin(), lst.end(), x);
14 }
15
16 bool contains(int x) override {
17 return this->findElement(x)!=lst.end();
18 }
19
20 void insert(int x) override {
21 list<int>::iterator it=findElement(x);
22
23 if (it!=lst.end()) {
24 this->hitCount++;
25 lst.erase(it);
26 lst.push_back(x);
27 }
28 else {
29 if (this->full())
30 lst.pop_front();
31 lst.push_back(x);
32 }
33 }
34};
例: A B C D A B C D A B C D
Page Fault: 全是
Arrange physical pages in circle with single clock hand
Hardware "use" bit per physical page
On page fault
Advance clock hand
Check use bit
最差情况:转了一圈,1 全变 0,又回到最开始 (FIFO)
hit 的时候时针是不转的
稳定时,时针永远指向刚被替换的下一个位置
理论实现
xxxxxxxxxx
441class ClockCache : public Cache {
2 private:
3 vector<pair<int, int>> vec;
4 int ptr=0;
5
6 public:
7 ClockCache(int size) : Cache(size) {}
8
9 bool full() override {
10 return vec.size()==this->size;
11 }
12
13 int findElement(int x) {
14 for (int i=0;i<vec.size();i++)
15 if (vec[i].first==x)
16 return i;
17 return -1;
18 }
19
20 bool contains(int x) override {
21 return this->findElement(x)>=0;
22 }
23
24 void insert(int x) override {
25 int index=this->findElement(x);
26
27 if (index>=0) {
28 vec[index].second=1;
29 this->hitCount++;
30 }
31 else {
32 if (this->full()) {
33 while (vec[ptr].second!=0) {
34 vec[ptr].second=0;
35 ptr=(ptr+1)%this->size;
36 }
37 vec[ptr]=make_pair(x, 1);
38 }
39 else
40 vec.push_back(make_pair(x, 1));
41 ptr=(ptr+1)%this->size;
42 }
43 }
44};
Nth chance algorithm: Used bit 变成一个 counter,从 N 开始倒计
Split memory in two list
Access pages in Active list at full speed
Page Fault
全局置换 Global Replacement
process selects replacement frame from set of all frames; one process can take a frame from another
局部置换 Local Replacement
each process selects from only its own set of allocated frames
Equal Allocation (Fixed Scheme)
Proportional Allocation (Fixed Scheme)
Allocate according to the size of process
设 size of process
total # of frames
Allocation for is
Priority Allocation
Proportional scheme using priorities rather than size
Possible behavior: If process generates a page fault, select for replacement a frame from a process with lower priority number
文件系统 File System
Layer of OS that transforms block interface of disks (or other block devices) into Files, Directories, etc.
文件系统的功能
多级继承结构 Hierarchical Structure
Each directory entry is a collection of
Each has a name and attributes
Links (hard links) make it a DAG, not just a tree
文件 File
操作系统对存储设备的物理属性加以抽象,从而定义逻辑存储单位
Named permanent storage
文件的组成
Data
Blocks on disk somewhere
Metadata (Attributes)
Owner, size, last opened, …
Access rights
Basic entities on a disk
File
User visible group of blocks arranged sequentially in logical space
Directory
User visible index mapping names to files
Access disk as linear array of sectors
Need way to track free disk blocks
Need way to structure files: File header
连续分配方法要求每个文件在磁盘上占有一组连续的块。磁盘地址为磁盘定义了一个线性排序。有了这个排序,假设只有一个作业正在访问磁盘,在块 b 之后访问块 b+1 时通常不需要移动磁头。当需要磁头移动(从一个柱面的最后扇区到下一个柱面的第一个扇区时),只需要移动一个磁道
Locate Files
Start address and size -> easy to random access
Delete Files
缺点:外碎片 External Fragmentation
缺点:无法应对文件增长 File Growth Problem
连续分配的应用
Chop the storage device into equal sized blocks
Fill the empty space in a block by block manner
Leave 4 bytes from each block as the pointer
Keep the file size in the root directory table
缺点:内碎片 Internal Fragmentation
The last block of a file may not be fully filled
缺点:随机访问性能差
What if I want to access the 2019-th block of ubuntu.iso?
You have to access blocks 1~2018 of ubuntu.iso until the 2019-th block.
优点
索引分配通过将所有指针放在一起,即索引块 (Index Block),实现了高效的随机访问
索引块的组织方式
链接方案
一个索引块通常为一个磁盘块,本身可以读写,通过链表的形式存放大文件
多级索引
通过第一级索引块指向一组第二级索引块,它又指向文件块
组合方案
iNode
文件分配表 File Allocation Table
Centralize all the block links as FAT
FAT 相当于一个 next 数组
在 DOS 里 block 被称为 cluster
假设 block size = 32 KB,那么对于 FAT32 来说,它支持的文件总大小为
32 * 210 * 228 = 243 = 8 TB
然而,微软为了催人用 NTFS,手动把 FAT 文件系统大小的上限设为了 32 GB
如果你有一个 64 GB 的 U 盘,在 FAT 文件系统下你最多只能往里存 32 GB
但是你可以不用微软的工具格式化,用别的手段把它格式化成 FAT 就没有这个限制了
例: dir c:\windows
文件名被规范成了 8+3 的格式
FAT32 的最大文件大小
4G - 1 bytes
Directory entry is important
It stores the start cluster number.
It stores the file size
Without the file size, how can you know when you should stop reading a cluster?
It stores all file attributes
例: 顺序读取 C:\windows\gamedata.dat
例: 向 C:\windows\gamedata.dat
写入数据
例: 删除 C:\windows\gamedata.dat
实际上数据还在硬盘中,直到 de-allocated 的 cluster 被再次使用(覆盖)
所以会产生安全问题,如果删除的数据还没被覆盖,就能通过其他手段获取
Secure Disk Erase
一种简单的办法是把释放出的 cluster 直接全写成 0
数据恢复
既然还在硬盘里,就可以在没被覆盖之前恢复
首先要抓紧拔电源,然后拿下硬盘
Space efficient:
Delete
Lazy delete efficient
Insecure
designed for single user 20+ years ago
Deployment: (FAT32 and FAT12)
It is everywhere: CF cards, SD cards, USB drives
Search
Block addresses of a file may scatter discontinuously
To locate the 888-th block of a file?
Start from the first FAT entry and follow 888 pointers
The most commonly used file system in the world
iNode Table
An array of iNodes
Pointers are unbalanced tree based
iNode Metadata
12 direct pointers
Indirect Pointers
一个 pointer 4 个 bytes (实际上就是个 32 bit 的地址)
For Ext2 & Ext3:
Block Bitmap & iNode Bitmap
Block bitmap tells which block is allocated
iNode Bitmap
A bit string that represents if an iNode (index node) is allocated or not
Implies that the number of files in the file system is fixed
Block Group 的优点
Performance: spatial locality
Group iNodes and data blocks of related files together
Reliability
Superblock and GDT are replicated in each block group
可以互相校验
磁盘管理
Disk divided into block groups
例: 在 /dir1/
目录下创建 file1.dat
A hard link is a directory entry pointing to the iNode of an existing file
That file can accessed through two different pathnames
例: ln /home/csbtang/dir1/12.jpg /tmp/mylink
例: /
下有 20 个目录,/
有多少硬链接
20 sub directories: they have link ..
Root directory: .
and ..
pointing to itself
根目录比较特殊:..
指向自己,因为它没有上级目录
20 + 2 = 22 hard links
删除硬链接
就是把链接的 iNode 的 link count --,当 = 0 的时候就会被 deallocate
A symbolic link creates a new iNode
例: ln -s /home/csbtang /dir1/12.jpg /tmp/mylink
Symbolic link is pointing to a new iNode whose target's pathname are stored using the space originally designed for 12 direct block and the 3 indirect block pointers if the pathname is shorter than 60 characters
Use back a normal iNode + one direct data block to hold the long pathname otherwise
软链接的 iNode 把本来存 pointer 的位置用来存链接到的文件的路径,如果路径大于 60 bytes 就再用一个 direct block 存
硬链接和软链接比较
Hard link
Soft link or Symbolic Link
New Technology File System (NTFS)
Default on Microsoft Windows systems
Variable length extents
Everything (almost) is a sequence of <attribute: value>
pairs
Mix direct and indirect freely
Directories organized in B-tree structure by default
Master File Table
Extents
Variable length contiguous regions
Journaling for reliability 日志记录
小文件
直接把数据存在 MFT Entry 里,不需要 data block
中文件
大文件
定义
A memory-mapped file contains the contents of a file in virtual memory. This mapping between a file and memory space enables an application, including multiple processes, to modify the file by reading and writing directly to the memory
Traditional I/O involves explicit transfers between buffers in process address space to/from regions of a file
This involves multiple copies into caches in memory, plus system calls
Map the file directly into an empty region of our address space
Executable files are treated this way when we exec
the process
File System
File defined by header, called iNode
Naming: translating from user visible names to actual sys resources
Multilevel Indexed Scheme
File Allocation Table (FAT) Scheme
4.2 BSD Multilevel index files
File layout driven by freespace management
Deep interactions between memory management, file system, sharing
mmap()
: map file or anonymous segment to memory盘片 Platter
磁道 Track
每个 track 都有一个编号,一般 0 号指最外侧的 track
扇区 Sector
Sector 是磁盘存数据的最小 unit
通常一个 sector 的 size 比一个 block 要小
柱面 Cylinder
磁臂 Disk Arm
每分钟转数 Rotation Per Minute (RPM)
传输速率 Transfer Rate
驱动器和计算机之间的数据流的速率
定位时间 (Positioning Time) 或随机访问时间 (Random Access Time)
寻道时间 Seek Time
移动磁臂到柱面所需时间
旋转延迟 Rotational Latency
旋转磁臂到所要扇区所需的时间
Data R/W Time
Positioning Time + Transfer Time (transfer a block of bits (sector) under r/w head)
= Seek Time + Rotational Latency + Transfer Time
Disk Latency
Queueing Time + Controller time + Seek Time + Rotation Lantency + Transfer Time
例:
Assumptions
南方科技大学 计算机科学与工程系 11812804 董正
操作系统 Operating System前言 Preface第三章 进程 Process3.1 基本概念3.1.1 进程的概念3.1.2 进程的状态 Process States3.1.3 进程控制块 Process Control Block3.2 进程生命周期3.2.1 进程标识符 Process Identifier3.2.2 进程创建 Process Creation3.2.3 进程执行 Process Execution3.2.4 进程等待3.2.5 进程时间3.2.6 进程终止 Process Termination3.2.7 进程生命周期 Process Lifecycle第四章 线程 Thread4.1 线程的概念4.2 线程的组成4.3 线程和进程的区别4.4 线程的生命周期 Thread Lifecycle4.5 多线程进程 Multithreaded Process4.6 多线程调度4.7 Multiprocessing, Multithreading and Multiprogramming第五章 进程调度 Process Scheduling5.1 基本概念5.1.1 上下文切换 Context Switch5.1.2 调度队列5.1.3 调度程序 Scheduler5.1.4 Dispatcher5.2 调度准则5.3 调度算法 Scheduling Algorithm5.3.1 先到先服务调度 First-Come-First-Served (FCFS)5.3.2 最短作业优先调度 Shortest-Job-First (SJF)5.3.2.1 非抢占 (Non-Preemptive) SJF5.3.2.2 抢占 SJF5.3.3 轮转调度 Round Robin (RR)5.3.4 优先级调度 Priority Scheduling5.3.4.1 Multiple Queue Priority Scheduling第六章 同步 Synchronization6.1 进程间通信 Inter-Process Communication (IPC)6.2 临界区 Critical Section6.2.1 竞争条件 Race Condition6.2.2 临界区问题 Critical Section Problem6.2.3 临界区问题的要求6.3 临界区问题的解决方案 Solutions for Critical Section Problem6.3.1 硬件同步 (×) Hardware Synchronization6.3.2 基本自旋锁 (×) Basic Spin Lock6.3.3 Peterson's Solution6.3.4 信号量 Semaphore6.4 经典同步问题6.4.1 有界缓冲问题 Bounded-Buffer Problem6.4.2 读者-作者问题 Reader-Writer Problem6.4.3 哲学家就餐问题 Dining-Philosophers Problem第七章 死锁 Deadlock7.1 死锁的概念7.2 死锁的特征7.2.1 死锁的必要条件7.2.2 资源分配图 Resource-Allocation Graph7.3 死锁的处理方法7.4 死锁检测 Deadlock Detection7.4.1 死锁检测算法7.4.2 死锁恢复7.5 死锁预防 Deadlock Prevention7.6 死锁避免 Deadlock Avoidance7.6.1 安全状态7.6.2 资源分配图算法7.6.3 银行家算法 Banker's Algorithm第八章 内存管理策略8.1 背景8.1.1 Aspects of Memory Multiplexing8.1.2 地址绑定 Address Binding8.1.3 逻辑地址空间与物理地址空间8.1.4 动态加载 Dynamic Loading8.1.5 动态链接与共享库8.2 交换 Swap8.3 连续内存分配 Contiguous Memory Allocation8.3.1 Uniprogramming8.3.2 内存保护 Protection8.3.3 多分区方法 Multiple-Partition Method8.3.3 碎片 Fragmentation8.4 分段 Segmentation8.5 分页 Paging8.5.1 页表 Page Table8.5.2 共享页8.5.3 分层分页 Multilevel Paging8.5.4 分段+分页第九章 虚拟内存管理9.1 缓存 Cache9.2 转换表缓冲区 Transition Look-aside Buffer (TLB)9.3 请求调页 Demand Paging9.3.1 基本概念9.3.2 请求调页的性能9.4 页面置换 Page Replacement9.4.1 Cache Miss 的分类9.4.2 FIFO 页面置换9.4.3 最优页面置换 MIN9.4.4 LRU 页面置换9.4.5 近似 LRU 页面置换9.4.5.1 时钟算法 Clock Algorithm9.4.5.2 Second Chance List Algorithm9.5 帧分配 Frame Allocation9.5.1 全局分配与局部分配9.5.2 分配算法第十 & 十一章 文件系统 File System10.1 文件系统概念10.2 文件和目录 Files and Directories10.2.1 目录的组成10.2.2 文件10.3 磁盘管理策略10.4 目录分配10.4.1 连续分配 Contiguous Allocation10.4.2 链接分配 Linked Allocation10.4.3 索引分配 Index Allocation10.5 文件分配表 FAT10.5.1 FAT 的原理10.5.2 FAT 文件系统的大小10.5.3 FAT 文件系统结构10.5.4 FAT 文件遍历10.5.5 FAT Directory Entry10.5.6 FAT 读文件10.5.7 FAT 写文件10.5.8 FAT 删除文件10.5.9 总结10.6 iNode10.6.1 iNode 的原理10.6.2 iNode 的结构10.6.3 iNode 文件大小10.7 可扩展文件系统 Ext10.7.1 Ext 文件系统的大小10.7.2 Ext 文件系统结构10.7.3 Ext 的 iNode 结构10.7.4 Ext 删除文件10.7.5 硬链接 Hard Link10.7.6 符号链接 (软链接) Symbolic (Soft) Link10.8 NTFS10.8.1 NTFS 文件系统结构10.8.2 NTFS 文件存储10.9 内存映射文件 Memory Mapped File10.10 文件系统总结第十二章 大容量存储结构12.1 大容量存储结构概述12.1.1 磁盘 Magnetic Disk (Hard Disk)12.1.2 磁盘性能12.1.2 固态磁盘 Solid State Disk (SSD)12.2 磁盘调度 Disk Scheduling12.2.1 FCFS 调度12.2.2 SSTF 调度12.2.3 SCAN 调度12.2.4 C-SCAN 调度12.2.5 LOOK 与 C-LOOK 调度12.2.6 调度算法的选择第十三章 I/O 系统13.1 I/O 硬件13.2 CPU 访问 I/O 设备13.3 控制器与 I/O 设备的数据传输13.4 I/O 设备与 CPU 通信13.4.1 轮询 Polling13.4.2 I/O 中断 I/O Interrupt13.5 I/O 请求生命周期13.6 I/O 性能END
笔记结构基于《操作系统概念(第九版)》
Based on Operating System Concepts Ninth Edition
CPU 活动
进程 (Process) 是执行的程序
Process is a program in execution
进程还包括:
程序 (Program) 和进程
状态 | 英文 | 说明 |
---|---|---|
新的 | new | 进程正在创建 |
运行 | running | 指令正在执行 |
等待 | waiting/blocked | 进程等待发生某个事件,如 IO 完成或收到信号 |
就绪 | ready | 进程等待分配处理器 |
终止 | terminated | 进程已经完成执行 |
等待状态又分为
刚 fork 的进程都会变成 ready 状态
进程控制块 PCB (任务控制块 Task Control Block)
在内存 (Main Memory) 里
PCB 是系统感知进程存在的唯一标志
进程状态 Process State
程序计数器 PC
CPU 寄存器 CPU Register
CPU 调度信息 CPU-scheduling Infomation
进程优先级,调度队列的指针和其他调度参数
内存管理信息 Memory-management Infomation
基地址,界限寄存器的值,页表或段表等
记账信息 Accounting Infomation
CPU 时间,实际使用时间,时间期限,记账数据,作业或进程数量等
IO 状态信息 IO Status Infomation
分配给进程的 IO 设备列表,打开文件列表等
几个概念
task_struct
in Linux进程标识符 Process Identifier (PID)
系统的每个进程都有一个唯一的整数 PID
System call getpid()
: return the PID of the calling process
init
进程
PID = 1, 所有用户进程的父进程或根进程
代码位于 /sbin /init
它的第一个任务是创建进程 fork()+exec*()
System call fork()
: creates a new process by duplicating the calling process.
fork 出的子进程从 fork 调用的下一行开始执行(因为 PC 也复制了)
在代码中如何区分父进程和子进程
pid=fork()
, 则父进程中 pid
变量等于子进程的 PID,子进程中 pid=0
1if (!pid) {
2 // 只有子进程执行
3}
4else {
5 // 只有父进程执行
6}
父进程和子进程执行顺序不确定
fork
的流程, 内核空间的动作
复制 PCB
更新 PCB 和 task list
复制用户空间
return
System call exec*()
Example: ls -l
args[0]
是程序的名字
The process is changing the code that is executing and never returns to the original code.
exec*()
之后的代码不会执行了,因为调用之后该进程就去执行 exec
指定的程序了
User space 的信息被覆盖
Program Code
Memory
Register Value: 如 PC
Kernel space 的信息保留: PID, 进程关系等
exec*()
的内核执行过程
System call wait()
Suspend the calling process to waiting state and return (wakes up) when
Return immediately (i.e., does nothing) if
给子进程收尸 见 3.2.6
fork()+exec*()+wait()=system()
例: shell 里输入命令 -> 执行相应程序 -> 程序终止 -> 返回 shell
init
, 所有的进程都是 fork()+exec*()
来的实际时间 Real Time
Wall-clock time
用户时间 User Time
CPU 在用户空间花费的时间
系统时间 System Time
CPU 在内核空间花费的时间
User Time + Sys Time 决定了程序的性能 (Performance)
System call exit()
: terminate the calling process
exit()
的执行过程
Clean up most of the allocated kernel space memory
Clean up the exit process's user space memory
Notify the parent with SIGCHLD.
僵尸进程 Zombie Process
wait()
wait()
,这样的进程称为僵尸进程wait()
,僵尸进程的进程标识符和它在进程表中的条目就会释放子进程先终止,父进程再调用 wait()
也可以,SIGCHLD 不会消失,但是这段间隔内僵尸进程就一直存在、占用资源
Linux 系统中僵尸进程被标为 <defunct>
查看: ps aux | grep <defunct>
exit()
system call turns a process into a zombie when
The process calls exit()
The process returns from main()
The process terminates abnormally
这种情况下 kernel 会帮忙给他调用 exit()
The fork bomb
PID 是有限的,Linux 中 PID 最大值为 32768
cat / proc /sys/ pid_max
fork bomb (僵尸大军)
xxxxxxxxxx
41int main() {
2 while (fork());
3 return 0;
4}
孤儿进程 Orphan Process
wait()
就终止,子进程变成孤儿进程init
进程作为孤儿进程的父进程 (Re-parent)exit()
里完成,见下图init
进程定期调用 wait()
以便收集任何孤儿进程的退出状态,并释放孤儿进程标识符和进程表条目
forked
Ready
Running
Blocked
Interruptable waiting
Un-interruptable waiting
计网的程序里经常碰见,纯贵物,谁设计的抓紧埋了吧
Return back to ready
Terminated
Heavyweight Process
A process has a single thread of control
线程 Thread
A sequential execution stream within process
又称 Lightweight Process
多线程 Multithreading
A single program made up of a number of different concurrent (并发) activities
结构图
State shared by all threads in process/address space
State "private" to each thread
栈
Process | Thread |
---|---|
Process means any program is in execution. | Thread means segment of a process. |
Process takes more time to terminate. | Thread takes less time to terminate. |
It takes more time for creation. | It takes less time for creation. |
It also takes more time for context switching. | It takes less time for context switching. |
Process is less efficient in term of communication. | Thread is more efficient in term of communication. |
Process consume more resources. | Thread consume less resources. |
Process is isolated. | Threads share memory. |
Process is called heavy weight process. | Thread is called light weight process. |
Process switching uses interface in operating system. | Thread switching does not require to call a operating system and cause an interrupt to the kernel. |
If one process is blocked then it will not effect the execution of other process | Second thread in the same task couldnot run, while one server thread is blocked. |
Process has its own Process Control Block, Stack and Address Space. | Thread has Parents' PCB, its own Thread Control Block and Stack and common Address space. |
PCB 指向多个 TCB
Switching threads within a block is a simple thread switch
Switching threads across blocks requires changes to memory and I/O address tables
超线程 Hyper-Threading
超线程(hyper-threading)其实就是同时多线程(simultaneous multi-theading), 是一项允许一个CPU执行多个控制流的技术。它的原理很简单,就是把一颗CPU当成两颗来用,将一颗具有超线程功能的物理CPU变成两颗逻辑CPU,而逻辑CPU对操作系统来说,跟物理CPU并没有什么区别。因此,操作系统会把工作线程分派给这两颗(逻辑)CPU上去执行,让(多个或单个)应用程序的多个线程,能够同时在同一颗CPU上被执行。注意:两颗逻辑CPU共享单颗物理CPU的所有执行资源。因此,我们可以认为,超线程技术就是对CPU的虚拟化
多进程 Multiprocessing
Multiple CPUs
A computer using more than one CPU at a time.
多线程 Multithreading
Multiple threads per Process
多道程序设计 Multiprogramming
Multiple Jobs or Processes
A computer running more than one program at a time
切换 CPU 到另一个进程需要保存当前进程状态和恢复另一个进程的状态,这个任务称为上下文切换
当进行上下文切换时,内核会将旧进程的状态保存在其 PCB 中,然后加载经调度而要执行的新进程的上下文
上下文切换是纯粹的时间开销 (Overhead),因为 CPU 在此期间没有做任何有用工作
上下文切换非常耗时
什么时候 Context Switch
wait(), sleep()
等作业队列 Job Queue
包含所有进程
就绪队列 Ready Queue
等待运行的进程
PCB 构成的链表
设备队列 Device Queue
等待使用该 IO 设备的进程队列
每个设备都有
队列图 Queueing Diagram
圆圈代表服务队列的资源, 箭头代表系统内的进程流向
↓执行或分派 (Dispatch)
缓冲池
通常来说,对于批处理系统,提交的进程多于可执行的,这些进程被保存到大容量存储设备(如磁盘)的缓冲池,以便以后执行
调度程序 (调度器)
调度器 | 别名 | 作用 |
---|---|---|
长期调度程序 Long-term Scheduler | 作业调度程序 Job Scheduler | 从缓冲池中选择进程加载到内存 |
短期调度程序 Short-term Scheduler | CPU 调度程序 | 从 Ready Queue 中选择进程并分配 CPU |
中期调度程序 Medium-term Scheduler | 进程交换 |
进程分类
中文 | 英文 | 特点 |
---|---|---|
I/O 密集型进程 | I/O Bounded Process | 执行 I/O 比执行计算耗时 |
CPU 密集型进程 | CPU Bounded Process | 很少I/O, 执行计算用时长 |
长期调度程序需要选择这两种进程的合理组合才能最大化 CPU 和 IO 设备的利用
Dispatcher 是一个模块,用来将 CPU 控制交给由 CPU 调度程序选择的进程
功能
调度延迟 Dispatch Latency
Dispatcher 停止一个进程而启动另一个进程所需的时间
Dispatcher 和 Scheduler 的区别
中文书把 dispatcher 也翻译成调度程序,我真想一拳干碎你的眼镜
https://www.differencebetween.com/difference-between-scheduler-and-vs-dispatcher
https://www.geeksforgeeks.org/difference-between-dispatcher-and-scheduler
The key difference between scheduler and dispatcher is that the scheduler selects a process out of several processes to be executed while the dispatcher allocates the CPU for the selected process by the scheduler.
Properties | DISPATCHER | SCHEDULER |
---|---|---|
Definition | Dispatcher is a module that gives control of CPU to the process selected by short term scheduler | Scheduler is something which selects a process among various processes |
Types | There are no different types in dispatcher. It is just a code segment. | There are 3 types of scheduler i.e. Long-term, Short-term, Medium-term |
Dependency | Working of dispatcher is dependent on scheduler. Means dispatcher have to wait until scheduler selects a process. | Scheduler works independently. It works immediately when needed |
Algorithm | Dispatcher has no specific algorithm for its implementation | Scheduler works on various algorithm such as FCFS, SJF, RR etc. |
Time Taken | The time taken by dispatcher is called dispatch latency. | Time taken by scheduler is usually negligible. Hence we neglect it. |
Functions | Dispatcher is also responsible for: Context Switching, Switch to user mode, Jumping to proper location when process again restarted | The only work of scheduler is selection of processes. |
CPU 使用率
应该使 CPU 尽可能忙碌
吞吐量
一个时间单元内进程完成的数量
周转时间
从进程提交到完成的时间段称为周转时间 (Turnaround Time)
等待时间
在就绪队列中等待所花时间之和
响应时间
从提交请求到产生第一响应的时间
Number of Context Switches (from 课件)
尽可能少做上下文切换
字面意思
每个进程都有一个时间量 (Time Quantum) 或时间片 (Time Slice)
通常 10~100ms
当时间片用完时,该进程就会释放 CPU (相当于抢占)
调度程序选择下一个时间片 > 0 的进程
如果所有进程都用完了时间片,它们的时间片同时被 recharge 到初始值
就绪队列为循环队列,进程被依次执行
每个进程都有一个优先级
调度程序根据优先级选择进程
优先队列
分类
新进程到来时,重新 schedule (这里会发生抢占)
如果当前进程被抢占,它先出队再入队
Linux Scheduler
匿名管道 Pipe
信号 Signal
例: ls | less
IPC Models
User space 里的所有东西都不能 share,所以 pipe 之类的都在 kernel 里
临界区 Critical Section
每个进程有一段代码,进程在执行该段代码时可能修改公共变量、更新一个表、写一个文件等
进入区 Entry Section
进入临界区前,请求许可的代码段
退出区 Exit Section
剩余区 Remainder Section
互斥 Mutual Exclusion
如果一个进程在其临界区内执行,那么其他进程都不能在临界区内执行
进步 Progress
如果没有进程在临界区内执行,并且有进程需要进入临界区,那么只有那些不在剩余区内的进程可以参加选择,以便确定谁下次进入临界区,而且这种选择不能无限推迟
别让执行临界区的进程空着,除非大家都不想进临界区
有限等待 Bounded Waiting
从一个进程做出进入临界区的请求直到这个请求允许为止,其他进程允许进入其临界区的次数有上限
别让一个进程等一辈子
Lock-based
Spin-based Lock
Sleep-based Lock
pthread_mutex_lock
Lock-free
单核
正确,但是不能接受
如果有个进程在 CS 里写个死循环就全卡这了
多核
不正确,除非把所有核的中断全都禁止
原理
设置一个公共变量 turn
来决定哪个进程可以进 CS
太浪费 CPU
违反 Progress
多个进程一定是交替执行
如果一个进程不打算进 CS 但是另一个进程交出了权限,那就要等很长时间 (no progress)
Example: 这种情况下没人在 CS 里。不能让执行 CS 的进程空着
在 turn
的基础上新加一个布尔数组 interested
If I don't show interest
I let you all go
If we both show interest
Take turns
x1int turn;
2int interested[2] = {false, false};
3
4void lock(int process) {
5 int other = 1 - process;
6 interested[process] = true;
7 turn = other;
8 while (turn == other && interested[other]); // busy waiting
9}
10
11void unlock(int process) {
12 interested[process] = false;
13}
会产生优先级翻转问题 (Priority Invasion)
优先级
为什么 turn=other
不是 turn=process
我们假设是这样
xxxxxxxxxx
21turn=自己;
2while (turn==自己 && interested[别人]);
如果现在有三个进程
我们脸比较黑,这三个进程经过调度,都该执行 turn=自己
这一行
那么最终 turn
是几,就取决于调度器了
假设调度器就是按 的顺序调度的,那么最后 turn=3
现在我们检查 while
的条件
turn=3
, 前半句不成立, 不需要 waitturn=3
, 前半句不成立, 不需要 wait那么现在 都被许可进入 CS,违反了互斥原则
正确是这样:
xxxxxxxxxx
41turn=别人;
2while (turn==别人们 && interested[别人们]);
3// while ((turn==x && interested[x]) || (turn==y && interested[y]))
4// while (turn!=自己 && interested[别人们])
还是这个例子,我们假设 turn
的赋值是 1 给 2,2 给 3,3 给 1
turn=别人
这一行,还是按 123 的顺序调度的turn=1
while
的条件,只有 可以进 CS信号量是一个 Structure
int
,表示剩余多少资源可用xxxxxxxxxx
41typedef struct {
2 int value;
3 struct process *list;
4} semaphore;
Wait (P 操作)
xxxxxxxxxx
71wait(semaphore *s) {
2 s->value--;
3 if (s->value<0) {
4 add this process to s->list;
5 block();
6 }
7}
Post (V 操作)
xxxxxxxxxx
71post(semaphore *s) {
2 s->value++;
3 if (s->value<=0){
4 remove a process p from s->list;
5 wakeup(p);
6 }
7}
分类
二进制信号量 Binary Semaphore
只能 0 或 1
计数信号量 Counting Semaphore
可以 > 1
又称生产者-消费者问题 (Producer-Consumer Problem)
组成
Bounded Buffer
Producer Process
Consumer Process
要求
Producer
Consumer
例子
Semaphore 实现
xxxxxxxxxx
331semaphore mutex=1;
2semaphore avail=N;
3semaphore fill=0;
4
5void producer() {
6 int item;
7
8 while (true) {
9 item=produce_item();
10
11 wait(&avail);
12 wait(&mutex);
13
14 insert_item(item);
15
16 post(&mutex);
17 post(&fill);
18 }
19}
20
21void consumer() {
22 int item;
23
24 while (true){
25 wait(&fill);
26 wait(&mutex);
27
28 item=remove_item();
29
30 post(&mutex);
31 post(&avail);
32 }
33}
要求
问题描述
每个哲学家有两个可能的动作
如果一个哲学家要吃面条,他必须同时获得左右两根筷子
拿起来的筷子不会被别人抢
要求
设计一个 Protocol,保证所有哲学家
解决方案设计
在正常操作模式下,进程只能按如下顺序使用资源:
申请
进程请求资源。如果进程不能立即被允许,那么它应该等待,直到获取该资源
使用
进程对资源进行操作
释放
进程释放资源
死锁 Deadlock
Deadlock is a situation where a set of processes are blocked because each process is holding a resource and waiting for another resource acquired by some other process.
饥饿 Starvation
Indefinite Blocking
A condition in which a process is indefinitely delayed because other processes are always given preference.
Starvation is the problem that occurs when high priority processes keep executing and low priority processes get blocked for indefinite time.
Deadlock 一定会造成 starvation
互斥 Mutual Exclusion
Only one thread at a time can use a resource.
占有并等待 Hold and Wait
一个进程应占有至少一个资源并等待另一个资源,而该资源为其他进程所占有
非抢占 No Preemption
资源不能被抢占,即资源只能被进程在完成任务后自愿释放
循环等待 Circular Wait
有一组等待进程
注意是必要条件,即使这些条件都满足也不一定死锁,还需要运气比较背
圆表示进程
矩形表示资源
矩形内的点表示资源实例
申请边 Request Edge
进程指向资源的边
分配边 Assignment Edge
资源指向进程的边
如果分配图没有环,那么系统一定没有死锁;如果有环,那么可能存在死锁
死锁的例子
有环没死锁的例子
让 先执行完
通过协议来预防或避免死锁,确保系统不会进入死锁状态
允许系统进入死锁状态,然后检测并恢复
忽视,认为死锁不可能在系统内发生
这种方案被 Linux, Windows 等大多数 OS 采用
就算出现了死锁,OS 也不管
[xxx] 表示数组
xxxxxxxxxx
131[Avail] = [FreeResources]
2Add all nodes to UNFINISHED
3
4do {
5done = true
6Foreach node in UNFINISHED {
7if ([Request_node] <= [Avail]) {
8remove node from UNFINISHED
9[Avail] = [Avail] + [Alloc_node]
10done = false
11}
12}
13} until(done)
当检测到死锁后:
进程终止
Terminate thread, force it to give up resources
资源抢占
Preempt resources without killing off process
回滚
Roll back actions of deadlocked threads
Many operating systems use other options
核心:打破四个必要条件
互斥
持有且等待
无抢占
如果一个进程持有资源并申请一个不能被立即分配的资源,那么它现在分配的资源都可以被抢占
相当于把它现有的资源都释放了
循环等待
需求边 Claim Edge
进程指向资源,虚线
进程 可能在将来申请某个资源
只有在将申请边变成分配边 (反向实线箭头) 并且不会导致资源分配图形成环时,才能允许申请
时间复杂度
, 为进程数量
个进程, 种资源
xxxxxxxxxx
121Add all nodes to UNFINISHED
2
3do {
4done = true
5Foreach node in UNFINISHED {
6if ([Max_node] - [Alloc_node] <= [Avail]) {
7remove node from UNFINISHED
8[Avail] = [Avail] + [Alloc_node]
9done = false
10}
11}
12} until(done)
例: 可以按 0213 或 0231 的顺序执行完
现在有个新的 ,比如
检查
检查
假设把资源分配给
一个内存,多个进程,怎么管理
Protection
Prevent access to private memory of other processes
Controlled Overlap
Sometimes we want to share memory across processes
Translation
Ability to translate accesses from one address space (virtual) to a different one (physical)
源程序中的地址通常是用符号表示 (如变量 count
)。编译器通常将这些符号地址绑定 (bind) 到可重定位的地址 (如“从本模块开始的第 14 字节”)。链接程序或加载程序再将这些可重定位的地址绑定到绝对地址 (如 74014)。每次绑定都是一个从一个地址空间到另一个地址空间的映射。
通常,指令和数据绑定到存储器地址可以在任何一步进行:
编译时 Compile Time
如果在编译时就已经知道进程将在内存中的驻留地址,那么就可以生成绝对代码 (Absolute Code)
例: MS-DOS 的 .COM 格式程序
加载时 Load Time
如果在编译时并不知道进程将驻留在何处,那么编译器就应生成可重定位代码 (Relocatable Code)。对这种情况,最后绑定会延迟到加载时进行
执行时 Runtime time
如果进程在执行时可以从一个内存段移到另一个内存段,那么绑定应延迟到执行时才进行
大多数通用 OS 采用
逻辑地址 Logical Address = 虚拟地址 Virtual Address
CPU 生成的地址
物理地址 Physical Address
真正的内存地址,加载到内存地址寄存器 (Memory-Address Register) 的地址
编译时和加载时的地址绑定会生成相同的逻辑地址和物理地址
执行时的绑定生成不同的逻辑地址和物理地址
内存管理单元 MMU
从虚拟地址到物理地址的运行时映射是由内存管理单元 (Memory Management Unit) 的硬件设备来完成 (包括查页表之类的都是 MMU 干的)
大多数 on-chip
动态链接的概念与动态加载相似。只是这里不是将加载延迟到运行时,而是将链接延迟到运行时。这一特点通常用于系统库,如语言子程序库。没有这一点,系统上的所有程序都需要一份语言库的副本,这一需求浪费了磁盘空间和内存空间。
存根 Stub
如果有动态链接,二进制镜像中每个库程序的应用都有一个存根(stub)。存根是一小段代码,用以指出如何定位适当的内存驻留的库程序,或如果该程序不在内存中应如何安装入库。不管怎样,存根会用子程序地址来代替自己,并开始执行子程序。因此,下次再执行该子程序代码时,就可以直接进行,而不会因动态链接产生任何开销。采用这种方案,使用语言库的所有进程只需要一个库代码副本就可以了。
举例来说,你在程序里调用了 STL 里的 Map,如果没有动态链接,就相当于你把 STL 里 Map 的源文件复制一份到了你的项目里。在动态链接下,不管多少程序调用,都只会调用那一份代码。
动态连接也可用于库更新。一个库可以被新的版本所替代,且使用该库的所有程序会自动使用新的版本。没有动态链接,所有这些程序必须重新链接以便访问。
Refer to 进程调度 5.1.3 中期调度程序
进程需要在内存中以便执行。进程也可以暂时从内存中交换 (swap) 到备份存储 (backing store,一般是磁盘) 上,当需要再次执行时在调回到内存中。
将内存分为多个分区,每个分区分给一个进程
固定分区 Fixed-size Partition
Each process has same memory size
可变分区 Variable Partition
动态存储分配问题 Dynamic Storage-Alloction Problem
当新进程需要内存时,系统为该进程查找足够大的孔
如果孔太大,那么就分为两块
进程终止时,释放内存,该内存合并回孔的集合
如果新孔与其他孔相邻,则合并成大孔
系统检查是否有等待内存空间的进程,以及新合并的孔能否满足等待进程等
从可用孔中选择一个分配的常用方法
首次适应 First-fit
分配首个足够大的孔
最优适应 Best-fit
分配最小的足够大的孔
最差适应 Worst-fit
分配最大的足够大的孔
内碎片 Internal Fragmentation
分配给进程的内存比所需的大,多余的那一部分就是内碎片
外碎片 External Fragmentation
两个进程之间的空闲孔,而且这个孔太小,没法分配给别的进程
紧缩 Compaction
移动已分配的内存,使得所有外碎片合并成一大块
只有在运行时绑定才可以使用紧缩,因为要重写基地址寄存器和界限寄存器
逻辑地址空间由一组段构成,每个段有名称和长度
地址指定了段名称和段内偏移 (Offset)
逻辑地址由有序对组成 <段号,偏移>
段表 Segment Table
在 CPU 里
每个进程都有一个
段表的每个条目包含:
图上没有 Check Valid 的内容
例 1:
例 2:
不多说,全是计组学过的内容
注意第一条指令 load address 取的是虚拟地址 0x4050, 物理地址只有真正访问内存的时候才翻译过去
分段的特点
Virtual address space has holes
When it is OK to address outside valid range?
Need protection mode in segment table
Fragmentation
What must be saved/restored on context switch?
每个逻辑地址分为两部分
与分段对比
页表条目
在内存里
每个进程一个
分页可以消除外碎片
一页的大小需要 trade off
What needs to be switched on a context switch? +Page table pointer and limit
Core Map
Do we need a reverse mapping (i.e. physical page -> virtual page)?
注意这里,比如 level 1 offset 10 位,那么二级页表最多可能有 个
当然大部分情况都是 < 1024 的,这就是多级页表的作用,解决了之前单个页表里一大堆 null 没用还占地方的问题
Tree of tables
What must be saved/restored on context switch?
共享
Cache
A repository for copies that can be accessed more quickly than the original
平均访问时间 Average Access time
注意这里跟计组学的不一样,访问 cache 然后没找到的时间没算进去
计组:
时间局部性 Temporal Locality
If you used some data recently, you will likely use it again
Keep recently accessed data items closer to processor
空间局部性 Spatial Locality
If you used some data recently, you will likely access its neighbors
Move contiguous blocks to the upper levels
其他内容详见计组课件
Cache 的应用
Page Table Entry (PTE) 的 cache
在 CPU 里
TLB Miss 的处理 (以下来自计组课件 永远滴神)
If page is in memory
Load the PTE from memory and retry
Could be handled in hardware
Or in software
If page is not in memory (page fault)
TLB 也可以多级 (L1, L2, ...)
TLB + Cache
Does software loaded TLB need use bit?
定义
Keep all pages of the frames in the secondary memory (外存) until they are required.
A page is delivered into the memory on demand i.e., only when a reference is made to a location on that page.
为什么要请求调页
内存相当于外存的 cache
缺页错误 Page Fault
对标记为无效 (valid bit) 的页面访问
缺页错误的处理
概括
具体
陷入操作系统 (trap)
保存寄存器和进程状态
确定中断是否为缺页错误
检查页面是否合法,并确定页面的磁盘位置
从磁盘读入页面到空闲帧
在等待时,将 CPU 分配给其他用户
收到来自 IO 子系统的中断 (IO 完成)
保存其他用户的寄存器和进程状态
确认中断是来自上述磁盘的
修正页表和其他表,以表示所需页面现在已在内存中
等待 CPU 再次分配给本进程
恢复用户寄存器、进程状态和新页表,再重新执行中断的指令
课件
D=1
), write contents back to diskOS 如何拿到一个空闲帧
Keeps a free list
Unix runs a "reaper" if memory gets too full
As a last resort, evict a dirty page first
有效访问时间 Effective Access Time
: 缺页错误率 Page Fault Rate
: 内存访问时间
注意这里课件和书上不一样,书上是 ,一个破公式就不能统一一下??
Compulsory Miss (Cold Start Miss)
Pages that have never been paged into memory before
How might we remove these misses?
Capacity Miss
Not enough memory. Must somehow increase available memory size
Conflict Miss
Policy Miss
Throw out oldest page. Be fair let every page live in memory for sameamount of time.
Bad: may throw out heavily used pages instead of infrequently used
理论实现:队列
xxxxxxxxxx
261class FIFOCache : public Cache {
2 private:
3 list<int> lst;
4
5 public:
6 FIFOCache(int size) : Cache(size) {}
7
8 bool full() override {
9 return lst.size()==this->size;
10 }
11
12 bool contains(int x) override {
13 return find(lst.begin(), lst.end(), x)!=lst.end();
14 }
15
16 void insert(int x) override {
17 if (this->contains(x)) {
18 this->hitCount++;
19 }
20 else {
21 if (this->full())
22 lst.pop_front();
23 lst.push_back(x);
24 }
25 }
26};
例: 3 个 frame,4 个 page,访问顺序: A B C A B D A D B C B
Page Fault: 7
Bélády 异常 (Bélády's Anomaly)
对于 FIFO 策略,Mem size 增大,page fault 有可能反而变多
置换最长时间不会使用的页面 (farthest-in-the-future)
Offline 算法,需要提前知道访问序列
理论天花板,实际不可能
理论实现: 好多实现方式
xxxxxxxxxx
571class MINCache : public Cache {
2 private:
3 set<int> s;
4 priority_queue<pair<int, int>> pq; // <index, pagenumber>
5
6 vector<int> pages;
7 vector<int> nxt;
8
9 public:
10 MINCache(int size) : Cache(size) {}
11
12 bool full() override {
13 return s.size()==this->size;
14 }
15
16 bool contains(int x) override {
17 return s.find(x)!=s.end();
18 }
19
20 void init(int n) {
21 int pageNum;
22 for (int i=0;i<n;i++) {
23 cin>>pageNum;
24 pages.push_back(pageNum);
25 nxt.push_back(INT_MAX);
26 }
27
28 map<int, int> temp;
29 for (int i=n-1;i>=0;i--) {
30 map<int, int>::iterator p=temp.find(pages[i]);
31 if (p!=temp.end())
32 nxt[i]=p->second;
33 temp[pages[i]]=i;
34 }
35 }
36
37 void insert(int i) override {
38 if (this->contains(pages[i]))
39 this->hitCount++;
40 else {
41 if (this->full()) {
42 auto t=pq.top();
43 pq.pop();
44 s.erase(t.second);
45 }
46
47 s.insert(pages[i]);
48 }
49
50 pq.push(make_pair(nxt[i], pages[i]));
51 }
52
53 void start() {
54 for (int i=0;i<pages.size();i++)
55 this->insert(i);
56 }
57};
例:A B C A B D A D B C B
Page Fault: 5
最近最少使用 Least Recently Used
Replace page that has not been used for the longest time
理论实现:双向链表
xxxxxxxxxx
341class LRUCache : public Cache {
2 private:
3 list<int> lst;
4
5 public:
6 LRUCache(int size) : Cache(size) {}
7
8 bool full() override {
9 return lst.size()==this->size;
10 }
11
12 list<int>::iterator findElement(int x) {
13 return find(lst.begin(), lst.end(), x);
14 }
15
16 bool contains(int x) override {
17 return this->findElement(x)!=lst.end();
18 }
19
20 void insert(int x) override {
21 list<int>::iterator it=findElement(x);
22
23 if (it!=lst.end()) {
24 this->hitCount++;
25 lst.erase(it);
26 lst.push_back(x);
27 }
28 else {
29 if (this->full())
30 lst.pop_front();
31 lst.push_back(x);
32 }
33 }
34};
例: A B C D A B C D A B C D
Page Fault: 全是
Arrange physical pages in circle with single clock hand
Hardware "use" bit per physical page
On page fault
Advance clock hand
Check use bit
最差情况:转了一圈,1 全变 0,又回到最开始 (FIFO)
hit 的时候时针是不转的
稳定时,时针永远指向刚被替换的下一个位置
理论实现
xxxxxxxxxx
441class ClockCache : public Cache {
2 private:
3 vector<pair<int, int>> vec;
4 int ptr=0;
5
6 public:
7 ClockCache(int size) : Cache(size) {}
8
9 bool full() override {
10 return vec.size()==this->size;
11 }
12
13 int findElement(int x) {
14 for (int i=0;i<vec.size();i++)
15 if (vec[i].first==x)
16 return i;
17 return -1;
18 }
19
20 bool contains(int x) override {
21 return this->findElement(x)>=0;
22 }
23
24 void insert(int x) override {
25 int index=this->findElement(x);
26
27 if (index>=0) {
28 vec[index].second=1;
29 this->hitCount++;
30 }
31 else {
32 if (this->full()) {
33 while (vec[ptr].second!=0) {
34 vec[ptr].second=0;
35 ptr=(ptr+1)%this->size;
36 }
37 vec[ptr]=make_pair(x, 1);
38 }
39 else
40 vec.push_back(make_pair(x, 1));
41 ptr=(ptr+1)%this->size;
42 }
43 }
44};
Nth chance algorithm: Used bit 变成一个 counter,从 N 开始倒计
Split memory in two list
Access pages in Active list at full speed
Page Fault
全局置换 Global Replacement
process selects replacement frame from set of all frames; one process can take a frame from another
局部置换 Local Replacement
each process selects from only its own set of allocated frames
Equal Allocation (Fixed Scheme)
Proportional Allocation (Fixed Scheme)
Allocate according to the size of process
设 size of process
total # of frames
Allocation for is
Priority Allocation
Proportional scheme using priorities rather than size
Possible behavior: If process generates a page fault, select for replacement a frame from a process with lower priority number
文件系统 File System
Layer of OS that transforms block interface of disks (or other block devices) into Files, Directories, etc.
文件系统的功能
多级继承结构 Hierarchical Structure
Each directory entry is a collection of
Each has a name and attributes
Links (hard links) make it a DAG, not just a tree
文件 File
操作系统对存储设备的物理属性加以抽象,从而定义逻辑存储单位
Named permanent storage
文件的组成
Data
Blocks on disk somewhere
Metadata (Attributes)
Owner, size, last opened, …
Access rights
Basic entities on a disk
File
User visible group of blocks arranged sequentially in logical space
Directory
User visible index mapping names to files
Access disk as linear array of sectors
Need way to track free disk blocks
Need way to structure files: File header
连续分配方法要求每个文件在磁盘上占有一组连续的块。磁盘地址为磁盘定义了一个线性排序。有了这个排序,假设只有一个作业正在访问磁盘,在块 b 之后访问块 b+1 时通常不需要移动磁头。当需要磁头移动(从一个柱面的最后扇区到下一个柱面的第一个扇区时),只需要移动一个磁道
Locate Files
Start address and size -> easy to random access
Delete Files
缺点:外碎片 External Fragmentation
缺点:无法应对文件增长 File Growth Problem
连续分配的应用
Chop the storage device into equal sized blocks
Fill the empty space in a block by block manner
Leave 4 bytes from each block as the pointer
Keep the file size in the root directory table
缺点:内碎片 Internal Fragmentation
The last block of a file may not be fully filled
缺点:随机访问性能差
What if I want to access the 2019-th block of ubuntu.iso?
You have to access blocks 1~2018 of ubuntu.iso until the 2019-th block.
优点
索引分配通过将所有指针放在一起,即索引块 (Index Block),实现了高效的随机访问
索引块的组织方式
链接方案
一个索引块通常为一个磁盘块,本身可以读写,通过链表的形式存放大文件
多级索引
通过第一级索引块指向一组第二级索引块,它又指向文件块
组合方案
iNode
文件分配表 File Allocation Table
Centralize all the block links as FAT
FAT 相当于一个 next 数组
在 DOS 里 block 被称为 cluster
假设 block size = 32 KB,那么对于 FAT32 来说,它支持的文件总大小为
32 * 210 * 228 = 243 = 8 TB
然而,微软为了催人用 NTFS,手动把 FAT 文件系统大小的上限设为了 32 GB
如果你有一个 64 GB 的 U 盘,在 FAT 文件系统下你最多只能往里存 32 GB
但是你可以不用微软的工具格式化,用别的手段把它格式化成 FAT 就没有这个限制了
例: dir c:\windows
文件名被规范成了 8+3 的格式
FAT32 的最大文件大小
4G - 1 bytes
Directory entry is important
It stores the start cluster number.
It stores the file size
Without the file size, how can you know when you should stop reading a cluster?
It stores all file attributes
例: 顺序读取 C:\windows\gamedata.dat
例: 向 C:\windows\gamedata.dat
写入数据
例: 删除 C:\windows\gamedata.dat
实际上数据还在硬盘中,直到 de-allocated 的 cluster 被再次使用(覆盖)
所以会产生安全问题,如果删除的数据还没被覆盖,就能通过其他手段获取
Secure Disk Erase
一种简单的办法是把释放出的 cluster 直接全写成 0
数据恢复
既然还在硬盘里,就可以在没被覆盖之前恢复
首先要抓紧拔电源,然后拿下硬盘
Space efficient:
Delete
Lazy delete efficient
Insecure
designed for single user 20+ years ago
Deployment: (FAT32 and FAT12)
It is everywhere: CF cards, SD cards, USB drives
Search
Block addresses of a file may scatter discontinuously
To locate the 888-th block of a file?
Start from the first FAT entry and follow 888 pointers
The most commonly used file system in the world
iNode Table
An array of iNodes
Pointers are unbalanced tree based
iNode Metadata
12 direct pointers
Indirect Pointers
一个 pointer 4 个 bytes (实际上就是个 32 bit 的地址)
For Ext2 & Ext3:
Block Bitmap & iNode Bitmap
Block bitmap tells which block is allocated
iNode Bitmap
A bit string that represents if an iNode (index node) is allocated or not
Implies that the number of files in the file system is fixed
Block Group 的优点
Performance: spatial locality
Group iNodes and data blocks of related files together
Reliability
Superblock and GDT are replicated in each block group
可以互相校验
磁盘管理
Disk divided into block groups
例: 在 /dir1/
目录下创建 file1.dat
A hard link is a directory entry pointing to the iNode of an existing file
That file can accessed through two different pathnames
例: ln /home/csbtang/dir1/12.jpg /tmp/mylink
例: /
下有 20 个目录,/
有多少硬链接
20 sub directories: they have link ..
Root directory: .
and ..
pointing to itself
根目录比较特殊:..
指向自己,因为它没有上级目录
20 + 2 = 22 hard links
删除硬链接
就是把链接的 iNode 的 link count --,当 = 0 的时候就会被 deallocate
A symbolic link creates a new iNode
例: ln -s /home/csbtang /dir1/12.jpg /tmp/mylink
Symbolic link is pointing to a new iNode whose target's pathname are stored using the space originally designed for 12 direct block and the 3 indirect block pointers if the pathname is shorter than 60 characters
Use back a normal iNode + one direct data block to hold the long pathname otherwise
软链接的 iNode 把本来存 pointer 的位置用来存链接到的文件的路径,如果路径大于 60 bytes 就再用一个 direct block 存
硬链接和软链接比较
Hard link
Soft link or Symbolic Link
New Technology File System (NTFS)
Default on Microsoft Windows systems
Variable length extents
Everything (almost) is a sequence of <attribute: value>
pairs
Mix direct and indirect freely
Directories organized in B-tree structure by default
Master File Table
Extents
Variable length contiguous regions
Journaling for reliability 日志记录
小文件
直接把数据存在 MFT Entry 里,不需要 data block
中文件
大文件
定义
A memory-mapped file contains the contents of a file in virtual memory. This mapping between a file and memory space enables an application, including multiple processes, to modify the file by reading and writing directly to the memory
Traditional I/O involves explicit transfers between buffers in process address space to/from regions of a file
This involves multiple copies into caches in memory, plus system calls
Map the file directly into an empty region of our address space
Executable files are treated this way when we exec
the process
File System
File defined by header, called iNode
Naming: translating from user visible names to actual sys resources
Multilevel Indexed Scheme
File Allocation Table (FAT) Scheme
4.2 BSD Multilevel index files
File layout driven by freespace management
Deep interactions between memory management, file system, sharing
mmap()
: map file or anonymous segment to memory盘片 Platter
磁道 Track
每个 track 都有一个编号,一般 0 号指最外侧的 track
扇区 Sector
Sector 是磁盘存数据的最小 unit
通常一个 sector 的 size 比一个 block 要小
柱面 Cylinder
磁臂 Disk Arm
每分钟转数 Rotation Per Minute (RPM)
传输速率 Transfer Rate
驱动器和计算机之间的数据流的速率
定位时间 (Positioning Time) 或随机访问时间 (Random Access Time)
寻道时间 Seek Time
移动磁臂到柱面所需时间
旋转延迟 Rotational Latency
旋转磁臂到所要扇区所需的时间
Data R/W Time
Positioning Time + Transfer Time (transfer a block of bits (sector) under r/w head)
= Seek Time + Rotational Latency + Transfer Time
Disk Latency
Queueing Time + Controller time + Seek Time + Rotation Lantency + Transfer Time
例:
Assumptions
Read sector from random place on disk
Seek Time + Rotational Latency + Transfer Time = 5 + 4 + 0.26 = 9.26 ms
Approx 10ms to fetch/put data: 100 KByte /sec
Read sector from random place in same cylinder
Rotational Latency + Transfer Time = 4 + 0.26 = 4.26 ms
Approx 5ms to fetch/put data: 200 KByte /sec
Read next sector on same track
Transfer Time = 0.26 ms
4 MByte /sec
Typical Numbers for Magnetic Disk
Given a sequence of access pages in the HDD
How to minimize seek time?
First come, first service
Total head movement distance = 640
最短寻道时间优先 Shortest-Seek-Time-First
Total distance = 236
Total distance = 236
Total distance = 382
但是它的 avg wait time 比较小
C-LOOK:
Total distance = 350
端口 Port
设备与计算机的通信连接点
数据输入寄存器 Data-in Register
被主机读出以获取数据
数据输出寄存器 Data-out Register
被主机写入以发送数据
状态寄存器 Status Register
包含一些主机可以读取的位,表示一些状态,如当前命令是否已完成
控制寄存器 Control Register
可由主机写入,以便启动命令或更改设备模式
总线 Bus
一组线路和通过线路传输信息的严格定义的一个协议
PCI 总线
扩展总线 Expansion Bus
SCSI 总线
控制器 Controller
可以操作端口、总线或者设备的一组电子器件
磁盘控制器 Disk Controller
SCSI 控制器
主机适配器 Host Adapter 或单独的电路板
以下为课件内容,我实在不知道该放在哪一节了
Operational Parameters for I/O
Data granularity: Byte vs. Block
Access pattern: Sequential vs. Random
Some devices must be accessed sequentially (e.g., tape)
Others can be accessed “randomly” (e.g., disk, cd, etc.)
Some devices require continual monitoring
Others generate interrupts when they need service
Transfer Mechanism: Programmed IO and DMA
CPU 与 Contorller 交互
控制器有一个或多个寄存器,用于数据和控制信号
处理器通过读写这些寄存器的位模式来与控制器通信
I/O Instuction
通过特殊 IO 指令针对 IO 端口地址传输一个字节或字
IO 指令触发总线线路,选择适当设备,并将位移入或移出设备寄存器
内存映射 (Memory Mapped) I/O
设备控制寄存器被映射到处理器的地址空间
处理器执行 IO 请求是通过标准数据传输指令读写映射到内存的设备控制器
例: Memory Mapped Display Controller
Hardware maps control registers and display memory into physical address space
Simply writing to display memory (also called the "frame buffer") changes image on screen
Writing graphics description to cmd queue
Writing to the command register may cause onboard graphics hardware to do something
Can protect with address translation
程序控制 (Programmed) I/O
直接内存访问 Direct Memory Access (DMA)
OS periodically checks a device specific status register
Pro: low overhead
Con: may waste many cycles on polling if infrequent or unpredictable I/O operations
主机与控制器之间的握手协调:
在步骤 1 中,主机一直处于忙等待 (busy waiting) 或轮询 (polling)。在该循环中,一直读取状态寄存器,直到忙位被清除
CPU 硬件有一条中断请求线 (Interrupt-Request Line, IRL)。CPU 在执行完每条指令后,都会检测 IRL。当 CPU 检测到控制器已在 IRL 上发出了一个信号时,CPU执行状态保存并且跳到内存固定位置的中断处理程序 (Interrupt Handler Routine)。中断处理程序确定中断原因,执行必要处理,执行状态恢复,并且执行返回中断指令以便 CPU 回到中断前的执行状态。
总结:设备控制器通过 IRL 发送信号从而引起 (raise) 中断,CPU捕获 (catch) 中断并且分派 (dispatch) 到中断处理程序,中断处理程序通过处理设备来清除 (clear) 中断。
中断请求线 IRL: 两条
非屏蔽中断 (Nonmaskable Interrupt)
保留用于诸如不可恢复的内存错误等事件
可屏蔽中断 (Maskable Interrupt)
在执行不得中断的关键指令序列之前,它可以由 CPU 关闭。可屏蔽中断可由设备控制器用来请求服务
中断向量 Interrupt Vector
是一个地址,根据这个地址+偏移量来选择特定的中断处理程序
中断优先级 Interrupt Priority Level
Top-half/bottom-half interrupt architecture
https://stackoverflow.com/questions/45095735/top-halves-and-bottom-halves-concept-clarification
https://www.tutorialsdaddy.com/uncategorized/top-half-vs-bottom-half/
上半部 Top Half Handler (硬中断)
快速处理中断,它在中断禁止模式下运行,主要处理跟硬件紧密相关的或时间敏感的工作
下半部 Bottom Half Handler (软中断)
延迟处理上半部未完成的工作,通常以内核线程的方式运行
设备驱动 Device Driver
http://www.differencebetween.net/technology/difference-between-device-driver-and-device-controller
Device driver is a specialized software program running as part of the operating system that interacts with a device attached to a computer. It is just a code inside the OS that allows to be empowered with the specific commands needed to operate the associated device.
ioctl
system callResponse Time or Latency
Time to perform an operation(s)
Response Time = Queue + I/O device service time
Bandwidth or Throughput
Rate at which operations are performed (op/s)
Files: MB/s, Networks: Mb/s, Arithmetic: GFLOP/s
Effective BW per op = transfer size / response time
EffBW(n) = n / (S + n/B) = B / (1 + SB/n)
Start up or "Overhead"
Time to initiate an operation
Syscall overhead
Operating system processing
Controller Overhead
Device Startup
Queuing
Most I/O operations are roughly linear in bytes
例: Fast Network
影响最大带宽的因素
Bus speed
Device transfer bandwidth