操作系统复习

目录

操作系统复习

Von Neumann Architecture

input、output、cpu(控制单元CU、算术逻辑单元ALU)、memory

Von Neumann Bottleneck

冯·诺依曼瓶颈是指处理器(CPU)和存储器之间的通信带宽限制,导致处理器速度无法完全发挥,成为计算机系统性能的主要限制因素

Events

  • fault故障:同步异常、未预料的
  • syscall系统调用:同步异常、故意的
  • interrupt中断:异步中断、未预料的
  • software interrupt:异步中断、故意的

Processes

  • 五状态图、linux图

Process Control Block (PCB)

包含有关进程的所有信息,当进程未运行时,操作系统会保存进程的所有硬件执行状态(PC、SP、regs 等)

上下文切换时,更新PCB,使用下一个进程的PCB

Threads

Kernel vs. User Threads

内核线程调度好,开销大

Preemptive Scheduling

非抢占式线程必须自愿放弃调用yield,而抢占式调度使用定时器中断处理程序强制当前线程调用yield

Virtual Memory

见笔记

TLB快表

虚拟页号映射到物理页号的cache

  • 在上下文切换时,管理机制有两种:

    硬件管理(x86)/软件管理

Page replacement

NRU

Not Recently Used 最近未使用

工作原理

  1. 基于两个位标记:
    • R 位(Referenced):页面是否被访问过。
    • M 位(Modified):页面是否被修改过。
  2. 页面分类(4 类优先级):
    • Class 0R=0, M=0,未被访问或修改的页面(最优先置换)。
    • Class 1R=0, M=1,未被访问但已被修改的页面。
    • Class 2R=1, M=0,被访问过但未被修改的页面。
    • Class 3R=1, M=1,被访问且被修改的页面(最后置换)。
  3. 算法流程:
    • 定期由操作系统清零所有页面的 R 位(通过时钟中断实现)。
    • 在需要置换时,按优先级从 Class 0 到 Class 3 寻找页面。

FIFO

Belady’s Anomaly:增加内存页框的数量反而会导致页面置换次数增加

123412512345

SCR Second-Chance

  1. 页面访问位
    • 每个页面都有一个 R 位。
    • 当页面被访问时,硬件将其 R 位置为 1
  2. 置换时的操作
    • 检查当前页框的 R 位:
      • 如果 R = 1:将其清零,并将该页面放到队列末尾(相当于“第二次机会”)。
      • 如果 R = 0:直接将其替换为新页面。
    • 继续扫描,直到找到需要置换的页面。
  3. 循环队列
    • SCR 通常使用一个循环队列实现,指针(Clock Hand)在页框间循环移动。

clock

  1. 页面访问位
    • 每个页面都有一个访问位(R 位),当页面被访问时,硬件会将其访问位设置为 1
  2. 时钟指针
    • 页面以环形队列的形式排布,时钟指针从队列的一个位置开始扫描。
    • 每次置换时,指针按顺序扫描每个页面,并检查该页面的访问位。
  3. 置换过程
    • 如果页面的访问位 R = 1,表示该页面最近被访问过,指针将继续移动并清除该页面的访问位(R = 0),然后转到下一个页面。
    • 如果页面的访问位 R = 0,表示该页面较长时间未被访问,指针将替换该页面,加载新页面,并将指针指向下一个页面。
  4. 循环
    • 整个队列会形成一个循环,当指针扫描完一个周期后,重新回到队列的开始位置,继续检查和替换页面。

Least Recently Used (LRU)

  1. 页面访问记录
    • LRU 算法假设操作系统能够记录每个页面的访问顺序,或者能够确定哪些页面最近被使用过,哪些页面则很久没有使用。
  2. 置换策略
    • 当内存中没有足够的空间加载新的页面时,LRU 会选择 最久未被访问的页面(即最长时间没有被访问过的页面)进行置换。
  3. 实现方法
    • 使用链表:维护一个链表,最近访问的页面放在链表头,最久未访问的页面放在链表尾。每次访问一个页面时,将该页面移动到链表头部;当发生页面置换时,直接移除链表尾部的页面。
    • 使用栈:通过栈模拟访问顺序,栈顶是最近访问的页面,栈底是最久未访问的页面。

Simulating LRU in Software

  • NFU 使用一个counter跟踪每个页面被引用的频率:对于每个页面,每次时钟中断时,计数器都会添加上 R 位(0 或 1)

    问题:它永远不会忘记任何事情

  • Aging: A slight modification to NRU

    在添加 R 位之前,每个计数器都会右移 1 位
    R 位添加到最左边而不是最右边的位

Thrashing

Thrashing(抖动) 是操作系统中与 虚拟内存管理 相关的一个问题,指的是由于频繁的页面置换导致系统性能急剧下降的现象。当系统的物理内存不足以存放当前运行的进程所需要的页面时,操作系统会不断地从磁盘中加载页面到内存中,而这些页面很快又会被换出,从而导致大量的页面置换。这样,CPU 花费大量时间进行页面交换,而不是执行实际的计算任务,从而导致系统的 吞吐量急剧下降

working set

  • 工作集窗口大小:k

  • 工作集:t_k到t之前间隔k次reference,在此之间查询的所有页p

  • 工作集大小不是工作集窗口 k

  • 工作集大小随程序局部性而变化,希望工作集是进程在内存中需要的页面集,以防止严重缺页

  • 增长非线性:locality

  • 如果空闲页面数 > 某个挂起进程的工作集,
    则激活进程并映射其所有工作集(预分页)
    如果某个进程的工作集大小增加且没有空闲页面,
    则挂起进程并释放其所有页面

  • 算法流程:

    R=1,将时间置为当前时间

    R=0,不在working set,换出这页

    R=0,在working set,记录age最大的换出

WSClock

每个entry包含上次使用时间和引用位R,R=1置为0,R=0找一个entry不在工作集内并且clean,找到就替换,否则如果不在工作集内并且dirty,schedule写到硬盘继续找;最终没找到说明所有页面都在工作集中,那么此时只能选择一个干净的页面来换出,如果不存在干净页面就找一个页面写磁盘,然后换出。

Scheduling

MLFQ

  1. 初始化
    • 所有新进程通常被放入最高优先级队列。
  2. 时间片分配
    • 每个队列有不同的时间片长度,高优先级队列的时间片较短,低优先级队列的时间片较长。
    • 时间片长度递增可以减少低优先级任务的切换开销。
  3. 优先级下降
    • 如果一个进程用完了当前队列的时间片且未完成运行,它会被移到更低优先级的队列。
  4. 优先级提升
    • 长时间未被调度的进程可能会被提升到更高优先级队列,以避免 饥饿(Starvation)
  5. 调度规则
    • 优先运行高优先级队列中的进程。
    • 如果多个进程在同一个队列中,使用 FCFS(先来先服务)RR(轮转调度)

多处理器

  • master-slave / peer 优缺
  • Thread调度:
    1. Load Sharing 全局的thread队列,负载均匀分布在各个处理器上,无需集中调度程序,但是需要互斥锁和缓存运行状态
    2. Gang Scheduling 将一个进程中的所有线程同时分配到多个处理器上运行。它特别适用于需要频繁线程间通信的任务。同一任务的所有线程在同一时间被分配到处理器上,避免了线程间通信的延迟。
    3. Dedicated Processor Assignment 一个处理器处理一个进程所有的threads

Rate Monotonic Scheduling (RMS)

RMS用于周期型任务,周期越短优先级越高,利用率上线趋近ln(2)

EDF

选择当前具有最早截止时间的任务进行调度。

截止时间越近,优先级越高。

LLF

松弛时间越小,优先级越高

松弛时间计算公式

\(L_i = D_i - t - C_i\)

其中:

  • D_i:任务的截止时间。
  • t:当前时间。
  • C_i:任务的剩余执行时间。

Synchronization

When are Resources Shared

  1. Local variables are not shared
  2. Global variables and static objects are shared
  3. Dynamic objects and other heap objects (malloc) are shared

race example

foo(){x++;} bar(){x--;}
和多核/单核没有关系,x必须是全局变量

critical section 临界区

如:

ENTER CRITICAL SECTION
Access shared variables; // Critical Section;
LEAVE CRITICAL SECTION

Critical Section Requirements

  1. Mutual exclusion: 一次只能有一个进程进入
  2. Progress: 进入临界区的一定会离开,在临界区外的不能阻止进入
  3. Bounded waiting: 没有饥饿,等待的一定最终会进入
  4. Performance: 等待和进出的开销较小

Critical Section properties

  • Safety property: nothing bad happens

    上面的1

  • Liveness property : something good happens

    2/3

  • Performance property

  • Rule of thumb: 优先safety,但也不要忘了liveness

alternation

如:

turn = 1;
func1(){
	while(turn == 2);
	#critical section
	turn=2;
	#outside of critical section
}
func2(){
	while(turn == 1);
	#critical section
	turn=1;
	#outside of critical section
}

不work,因为只执行一个会无限循环

Peterson’s Algorithm

while (true) {
    ready1 = true;
    turn = 2;
    while (turn == 2 && ready2) ;
    #critical section
    ready1 = false;
    #outside of critical section
}
while (true) {
    ready2 = true;
    turn = 1;
    while (turn == 1 && ready1) ;
    #critical section
    ready2 = false;
    #outside of critical section
}

lock

spinlock

如:

void acquire (lock) {
    while (lock->held);
    lock->held = 1;
}
  • 进程处于忙等,一直while

  • 不work,可能两个进程同时退出while,需要原子操作或者关闭中断

  • test-and-set:原子操作,返回旧值并设置为1

    void acquire (lock) {
    	while (test-and-set(&lock->held));
    }
    
  • wasteful: 一直占用cpu,解决方法:call thread_yield to give up the CPU/ sleep and wakeup

Disabling Interrupts

void acquire (lock) {
	disable interrupts;
}
void release (lock) {
	enable interrupts;
}
  • 一个处理器,两个进程无法同时关中断

  • 多处理器中断独立,不work

  • 在临界区内不关中断:

    void acquire (lock) {
        Disable interrupts;
        while (lock->held) {
            put current thread on lock Q;
            Enable interrupts;
            block current thread;
            Disable interrupts;
        }
        lock->held = 1;
        Enable interrupts;
    }
    void release (lock) {
        Disable interrupts;
        if (Q) remove waiting thread;
        unblock waiting thread;
        lock->held = 0;
        Enable interrupts;
    }
    

lock的缺点

  • Spinlocks – inefficient
  • Disabling interrupts – can miss or delay important events, and do not work on multicores.

Semaphores

读者写者模型

可以有多个读者

// number of readers
int readcount = 0;
// mutual exclusion to readcount
Semaphore mutex = 1;
// exclusive writer or reader
Semaphore w_or_r = 1;
writer {
    P(w_or_r); // lock out readers
    Write;
    V(w_or_r); // up for grabs
}
reader {
    P(mutex); // lock readcount
    readcount ++; // one more reader
    if (readcount == 1)
    	P(w_or_r); // synch w/ writers
    V(mutex); // unlock readcount
    Read;
    P(mutex); // lock readcount
    readcount --; // one less reader
    if (readcount == 0)
    	V(w_or_r); // up for grabs
    V(mutex); // unlock readcount}
}

问题:starvation,可以写者优先

semaphore的缺点

  • 本质上是共享的全局变量,可以在程序中的任何位置访问
  • 信号量与信号量控制的数据之间没有联系
  • 同时用于临界区(互斥)和协调(调度)
  • 无法保证正确使用

Monitor

  • monitor封装了共享数据、用这些数据的程序、进程间的同步机制
  • monitor里最多只有一个进程
  • 和临界区的区别:如果monitor里的进程block了,另一个进程可以进

Condition Variable

  • wait(condition, lock)

    释放锁并且等待,直到接收到signal,重新获取锁

    说明有等待队列

  • signal(condition) Wake up a thread

  • broadcast(condition) Wake all the thread

  • 不是布尔表达式

  • 和semaphore的区别:wait会block和释放锁,而P操作只会block;signal信号可能丢失,没有history,而V操作允许未来的进入

两种monitor

  • Hoare monitors:

    signal()会立即切换到wait的进程,需要保证一定正确

    if (empty)
    	wait(condition);
    
  • Mesa monitors:

    signal()把一个wait的进程放入monitor的ready queue,更小的上下文切换,更好实现广播

    while (empty)
    	wait(condition);
    

    读者写者实现:

    Monitor RW {
    int nr = 0, nw = 0;
    Condition canRead, canWrite;
    void StartRead () {
        while (nw != 0) do wait(canRead);
        nr++;
    }
    void EndRead () {
        nr--;
        if (nr==0) signal(canWrite)
    }
    void StartWrite {
        while (nr != 0 || nw != 0) do wait(canWrite);
        nw++;
    }
    void EndWrite () {
        nw--;
        signal(canWrite);
        broadcast(canRead);
    }
    } // end monitor
    

Messages and barriers

  • message issues:
    1. Message lost,ack lost
    2. Order
    3. Naming
    4. Authentication
  • Barriers:等待所有进程都到barrier处才都继续执行

UNIX Concurrency Mechanisms

  • Pipes

    进程间通过 producer-consumer model 通信的特殊的buffer,first-in-first-out queue,分命名和不命名两种

  • Messages

    msgsnd和msgrcv的syscall

  • Shared memory

    共享的虚拟内存,需由使用的进程提供同步机制

  • Semaphores

    semWait/semSignal,有一个信号量上阻塞的进程队列

  • Signals

    通过更新进程中的字段,如SIGINT

Linux Kernel Concurrency Mechanism

在UNIX的基础上还有:

  • Atomic Operations

    在integer和bitmap上的原子操作,有如add_and_test的操作

  • Spinlock

    A spinlock is an integer,循环检查是否为0 (spin)

  • Semaphores

    Linux的有

    • Binary semaphores
    • Counting semaphores
    • Reader-writer semaphores
  • Memory Barriers

    smp_mb(): 用于内存屏障,确保前后的所有读写操作顺序。

    smp_rmb(): 用于读屏障,确保屏障前的所有读操作先完成。

    smp_wmb(): 用于写屏障,确保屏障前的所有写操作先完成。

Bounded Buffer Problem

生产者消费者,buffer内的数量需要在0-n之间

producer {
	while (1) {
        Produce new resource;
        P(empty); // wait for empty buffer
        P(mutex); // lock buffer list
        Add resource to an empty buffer;
        V(mutex); // unlock buffer list
        V(full); // note a full buffer
    }
}
consumer {
    while (1) {
        P(full); // wait for a full buffer
        P(mutex); // lock buffer list
        Remove resource from a full buffer;
        V(mutex); // unlock buffer list
        V(empty); // note an empty buffer
        Consume resource;
    }
}
  • mutex and full/empty PV交换位置,会死锁

Dining Philosophers Problem

每个人如果先取左边再取右边,会死锁,需要同时取

The Sleeping Barber Problem

如果没有顾客,理发师去睡觉;顾客满座了会走,否则等待;sleep用down(&customers)实现

Semaphore Implementation

P(Semaphore S)
{
    PB(mutex);
    S.count--;
    if(S.count<0) {
        VB(mutex);
        PB(delay);
    }
    else
    	VB(mutex);
} 
V(Semaphore S)
{
    PB(mutex);
    S.count++;
    if(S.count<=0) {
    	VB(delay);
    }
    VB(mutex);
}

这样实现的问题是先连续多个VB(delay)后,只有一个PB(delay)得到响应,于是改成在PB(delay)后再释放V的mutex

P(Semaphore S)
{
    PB(mutex);
    S.count--;
    if(S.count<0) {
        VB(mutex);
        PB(delay);
    }
    VB(mutex);
} 
V(Semaphore S)
{
    PB(mutex);
    S.count++;
    if(S.count<=0) {
    	VB(delay);
    }else VB(mutex);
}

问题:效率低,阻塞V进程

Barz’s Solution:在P进程中链式地VB(delay),V只用VB(delay)第一个,count最低为0

P(Semaphore S)
{
    PB(delay);
    PB(mutex);
    S.count--;
    if(S.count>0) {
    	VB(delay);
    }
    VB(mutex);
}
V(Semaphore S)
{
    PB(mutex);
    S.count++;
    if(S.count==1) {
    	VB(delay);
    }
    VB(mutex);
}

还可以在P再开一个barrier互斥锁,让count最多为-1

Kearn’s solution: count正负都可以,count<=0时V操作记录wakecount,用于链式唤醒

P(Semaphore S)
{
    PB(mutex);
    S.count--;
    if(S.count<0) {
        VB(mutex);
        PB(delay);
        wakecount--;
        if(wakecount>0)
            VB(delay);
    }
    VB(mutex);
} 
V(Semaphore S)
{
    PB(mutex);
    S.count++;
    if(S.count<=0) {
    	wakecount++;
        if(wakecount==1)
            VB(delay);
    }
    VB(mutex);
} 

resource

  • reusable: e.g., CPU, memory, disk space, I/O devices, files

    acquire → use → release

  • Consumable: produced by a process, needed by a process; e.g., messages, buffers of information, interrupts

    create → acquire → use (consumed)

Deadlock

定义:一个进程集合中的进程都在等待集合中的其他进程进行某事件

可能导致死锁的某些情况:

  • Mutual exclusion 进程要求独占控制其所需资源
  • Hold-and-wait condition 进程持有已分配给它们的资源,同时等待其他资源
  • No preemption condition 不能从持有资源的进程中移除资源,直到使用完毕
  • Circular wait condition 存在一个循环的进程链,其中每个进程持有一个或多个资源,这些资源由链中的下一个进程请求

Resource Allocation Graph

RAG:进程节点指向申请的资源节点,资源节点指向分配到的进程,有cycle则说明可能有死锁,因为一种资源可能有多个unit

WFG:一种资源只有一个unit,只考虑进程节点构成的图,有环则有死锁

Dealing with Deadlocks

  • Ignore it - 鸵鸟算法,重启系统

  • Deadlock Prevention

    避免上面四种情况中断至少一种

    1. Two-Phase Locking,第一阶段获得所有需要的锁,第二阶段全部释放,类似一开始就申请所有资源

    2. Break Circular Wait Condition

      Method 1: 一次只获得一个资源,申请下一个时释放

      Method 2:申请资源按升序排序

    3. Summary

      Mutual Exclusion: 用缓存避免互斥的情况

      Hold and wait: 一开始就申请所有资源

      No preemption: 虚拟化之后可以抢占(如硬件)

      Circular wait: 给资源编号,按顺序申请

  • Deadlock Avoidance

    Banker’s algorithm:

    • 初始化:
      系统维护四个关键数据结构:Available、Max、Allocation、Need。

    • 请求资源:
      当某进程 P 提出资源请求 Request 时:

      检查 Request <= Need:确保请求不会超过进程的声明需求。
      检查 Request <= Available:确保请求不会超过系统当前的可用资源。 如果不满足这两个条件,则拒绝请求。

    • 试探性分配:
      如果满足条件,系统试探性地分配资源:

      Available = Available - Request
      Allocation[P] = Allocation[P] + Request
      Need[P] = Need[P] - Request

    • 安全性检查:
      使用安全性算法验证系统状态是否安全:

      初始化一个工作向量 Work,等于当前的 Available。
      标记所有进程的完成状态为 False。
      查找一个满足 Need[i] <= Work 且未完成的进程。
      如果找到,模拟进程完成,释放其资源到 Work 并标记为完成。
      如果所有进程均能完成,状态为安全。

    • 回滚或完成:

      如果状态安全,确认分配。
      如果状态不安全,回滚分配并拒绝请求。

  • Detection and Recovery

    Detection: 标记边进行搜索

    Recovery:

    1. 中止所有进程
    2. 一次中止一个进程,然后再运行一次探测
    3. 抢占资源,需要选择进程和资源,回滚被抢占的进程,还需要避免饥饿
  • livelock活锁

    发生阻塞时所有进程都在释放锁,然后又都申请锁,重复进行无用的操作

    解决方法:引入随机量

  • Non-Deadlock Bugs

    Atomicity-Violation:串行地内存访问一个地址,但是在中间被另一个线程改动了,解决方法:加锁

    Order-Violation:两个内存访问的执行顺序错误,解决方法:条件变量的wait和signal

File System

功能:

  • abstraction(files)
  • directories
  • sharing
  • protection

Files

Files: logical units of information created by processes

  • Contents, size, owner, last read/write time, protection, etc.
  • A file can also have a type
  • 可以是一段字节序列,或者一段记录序列,或者记录的树型结构

Directories

对于用户来说,它们提供了一种组织文件的结构化方式,对于文件系统,它们提供了一个方便的命名接口,允许实现将逻辑文件组织与磁盘上的物理文件位置分开

一个directory是<name, location>的一个list, usually unordered

Protection

Capabilities: 对每个主体(alice/bob/...)维护object的权限

ACL Access Control Lists:对每个object(file)维护每个主体的权限

ACL以对象为中心,易于授予、撤销,但是当大量共享时ACL会很大,因此unix使用用户组权限。

文件系统如何使用磁盘存储文件

  • 文件系统定义块大小 block size,如4kb
  • 需要一个master block决定根目录的位置,始终位于众所周知的磁盘位置,通常在磁盘上复制以确保可靠性
  • 需要一个free map确定哪些块是空的,而哪些块是已分配的,通常是bitmap,缓存到内存以提高性能
  • 剩下的块是空闲的

File System Layout

太小的文件也会使用一整个block,空的部分属于内部碎片

Contiguous Layout

  • 目录存储第一个块的地址,其他的块地址用offset可以算出来
  • written之后就难以grow a file
  • 删除之后会有gaps,产生外部碎片

Linked Layout

  • 每个block link到后一个block
  • 随机访问代价变大

indexed Layout

  • 索引块存储指向数据块的指针
  • 目录指向索引块
  • 大文件需要多个索引块

Unix inodes

  • inode包含文件元数据File size、 Protection bits、Reference count、Timestamps等
  • 然后包含15个块的指针,12个直接块,然后是一级/二级/三级索引指针
  • 文件大小最大为48k+4m+4g+4t

Master Block

  • 存储在事先定义的固定位置
  • 存储指向“/” inode 的指针

Free map blocks

  • store a bitmap, one bit per block

总结:Master block 、Bitmap blocks 、Inode blocks 、Data blocks 一共四种block

路径翻译

用master block获得根目录的inode,然后每个目录的inode可以查找目录下文件的块号,最后加载目标文件的inode,获得第一个数据块的地址

ln –s file alias Syscall:symlink()

当遇到软链接时,重新进行路径翻译(使用链接到的地址)

实现:将别名作为字符串存储在文件中,并将它的 inode 标记为一个软链接

ln file alias Syscall:link()

创建硬链接会添加另一个目录条目,将新名称映射到与旧名称相同的 inode,向 inode 添加一个新指针或链接,inode 中的引用计数也会增加

软链接与硬链接的区别

  • 与软链接不同,硬链接使用同一个inode,而软链接使用新的inode
  • 软连接可以跨文件系统,硬链接不行
  • 硬链接性能更好
  • 硬链接不允许链接目录(会造成无限深度访问,父目录不唯一,一个文件多个目录),软链接可以

文件操作

  • 创建文件:分配inode,初始化,在目录entry里创建映射,进程写时再分配数据块
  • 另一种分配方法:Extent Allocation,extent是一块连续的地址,这样一段地址只需要储存开头和结尾的两个数字,减少文件碎片和元数据开销;示例 FS:ext4、JFS、btrfs、NTFS
  • 重命名文件:
    • 使用新名称,复制内容,然后删除旧文件
    • 或者创建一个新的目录条目,只改变名称,仅修改目录,文件和 inode 保持不变
    • 系统调用:rename()
  • 删除文件
    • 删除目录条目,系统调用unlink()
    • 减少 inode 中的引用计数,如果为 0 释放数据块和 inode 块
    • 如果文件仍在任何进程中打开,则目录条目会被删除,但文件块不会被删除,直到最后一个进程关闭这个文件

挂载Mouting

比如挂载home文件系统,挂载到根目录下/home,访问/home/username/file会在“根”文件系统中启动路径名转换,在跨挂载点时在“home”文件系统中继续;

大多数情况不可见,但无法跨文件系统进行硬链接

写回缓存

操作系统通常会进行写回缓存,维护未提交块的队列,定期将队列刷新到磁盘(30 秒阈值),以减少 IO 次数

  • 如果块在 30 秒内多次更改,则只需要一次 I/O;如果块在 30 秒之前被删除,则不需要 I/O
  • 不可靠但实用,崩溃时过去 30 秒内的所有写入都会丢失
  • 现代操作系统默认以提升性能
  • 系统调用(Unix:fsync)使应用程序能够强制将数据写入磁盘

预读取

FS 预测进程将请求下一个块,这样IO时间可能和计算上一个块的时间重合,提升效率;当进程请求块时,它将位于缓存中

Data Redundancy

A和B部分内容重合,提升可靠性,伤害容量且需要一致性(某些值的组合是非法的)

fsck

文件系统检查和修复

问题:如何修复文件系统映像并不总是显而易见的(不知道“正确”状态)、速度慢

Journaling General Strategy

写入时不删除旧data X,而是先写X的备份(以及redundant f(X)的备份),再把备份写入原本文件,这样任何时候都是good time to crash

FAT (File Allocation Table)

  • 核心结构是文件分配表,它位于存储设备的开头,用于记录每个文件的存储位置。

  • 存储设备被划分为固定大小的簇(文件存储的基本单位)。

    每个簇包含一个或多个扇区(sector)。

    FAT 使用簇号在表中定位文件数据。

  • 优点:简单高效

  • 缺点:碎片化、安全性

NTFS

  • 所有文件和目录的元数据都存储在一个特殊文件中(称为 Master File Table,MFT)。

    MFT 中包含文件名、文件权限、创建时间、数据位置等信息。MFT可以生长

  • 支持日志记录 Journaling 功能,记录文件系统的更改操作。

    在系统崩溃后,可以通过日志恢复文件系统的一致性。

  • 优点:安全性(efs文件加密,权限),文件压缩、通过日志系统提供可靠性和一致性

  • 缺点:开销较大、兼容性

IO

Block devices

块设备将信息存储在固定大小的块中,每个块都有自己的地址,如硬盘

Character devices

字符设备传递或接受字符流,而不考虑任何块结构,如打印机、鼠标、网络接口

Device controller

I/O 单元通常由机械部件和电子部件组成,电子部件称为设备控制器或适配器。

控制器的工作是将串行比特流转换为字节块,并在需要时执行错误更正

每个控制器都有几个寄存器用于与 CPU 通信;许多设备都有一个可以读取和写入的数据缓冲区

How to communicate with device controllers

Memory-Mapped I/O:将所有控制寄存器映射到内存空间,将 I/O 读取视为内存读取

优点:I/O 设备驱动程序可以完全用 C 编写,可以在内存中引用设备寄存器,缺点:需要有选择地禁用缓存

Separate I/O and memory space:需要访问单独的IO接口

专用内存总线 Dedicated Memory Bus

  • 单总线
  • 高速内存总线:需要区分访存和IO

Techniques for Performing I/O

  • Programmed I/O (PIO) 处理器发出 I/O 命令,可能需要忙等I/O操作完成,不需要中断

  • Interrupt-driven I/O 等待 I/O 时可以释放 CPU,I/O 操作完成时将生成中断,前两种都是用处理器进行I/O

  • DMA:处理器将 I/O 操作委托给 DMA 模块,DMA 模块直接传输数据到或读取内存,完成时 DMA 模块向处理器发送中断信号

    流程:CPU委托给DMA、DMA向设备申请、设备向内存传输、设备返回给DMA ack信号、DMA产生中断通知CPU

    Integrated DMA & I/O:每个IO设备集成DMA,提升效率

    Dedicated I/O Bus:专用IO总线,减少DMA模块数量(否则每个IO设备都有一个DMA)、方便扩展新的IO设备

  • I/O module as a separate processor、I/O module as a computer

Hierarchical Design

IO软件通常分四层,由低到高:

  • Interrupt handlers:唤醒驱动
  • Device drivers:设置设备的寄存器,检查状态,执行IO
  • Device-independent os software:缓存、提供接口、分配空间等其他
  • User-level I/O software:用户发出IO请求、Spooling

每层都有明确定义的功能,以及与相邻层明确定义的接口;每层都依赖于下一层来执行更原始的功能

Device drivers

通常由设备制造商编写并随设备一起交付,通常在操作系统内核中运行

Device-Independent I/O Software

为设备驱动程序提供统一接口、报告错误、缓存、分配和释放专用设备、提供块大小

IO Buffer

  • Block-oriented Device:输入传输到缓冲区,提前读取

  • Stream-oriented Single Buffer:如终端、鼠标

  • Double Buffer:

    当一个缓冲区(Buffer A)正在被数据生产者填充时,另一个缓冲区(Buffer B)可以被数据消费者处理。

    一旦 Buffer A 填满,生产者切换到 Buffer B;同时消费者开始处理 Buffer A 的数据。

    双缓冲实现了数据生产者和消费者的并行处理,减少了等待时间。

    如果进程执行快速突发的 I/O,则双缓冲可能不够

  • Circular Buffer:多个buffer

  • buffer可平滑 I/O 需求的峰值、可以提高操作系统的效率和各个进程的性能

User-Space I/O Software

系统调用、输入和输出的格式化(printf)

  • Spooling:用户进程在进行IO请求时将请求放在缓冲区中,由 daemon 进程决定何时进行请求,可以提高效率和实现设备共享

UNIX IO

Unbuffered I/O

  • 由DMA执行,最快
  • 进程被锁定在主内存中,无法交换出去
  • 设备与进程绑定,其他进程无法使用

Buffer Cache

本质上是磁盘缓存

Character Queue

只能读取一次,鼠标等设备

The Elevator Scheduler

用于改进磁盘臂disk arm调度

  • 维护磁盘读写请求的优先队列,按块号排序
  • 驱动器可朝一个方向移动以满足每个请求

Deadline Scheduler

有到期时间,到期后从FIFO队列调度,否则从排好序的队列调度

Anticipatory(预期) Scheduler

如果一个进程频繁执行小块的顺序读操作,上面的算法可能会造成性能下降

预期调度器会延迟几毫秒,假设同一个进程可能会发出后续的相关 I/O 请求。

  • 如果在等待时间内,来自同一进程的请求到达,则优先处理该请求。
  • 否则调度器继续服务其他进程的请求。

Linux Page Cache

使用统一虚拟页缓存和I/O缓存的好处:方便dirty page的写回

Windows I/O

Windows I/O 管理器负责操作系统的所有 I/O ,提供所有类型的驱动程序都可以调用的统一接口,与缓存管理器、各种驱动紧密合作

提供同步和不同步的IO

RAID

独立磁盘冗余阵列,冗余磁盘容量用于存储奇偶校验信息,从而提供磁盘故障的可恢复性

RAID 0

  • 无冗余,将数据分块,并交替存储在多个磁盘上。
  • 性能高:多个磁盘并行读写,速度提升明显。
  • 单盘故障导致数据丢失,仅适合高速存储需求。

至少需要2个磁盘

RAID 1

镜像存储,提供冗余,数据安全性高,但磁盘利用率低(仅 50%)。

至少需要2个磁盘

RAID 2

将数据按位分割,并存储在多个磁盘上,同时使用专用磁盘存储纠错码(基于海明码)。复杂性高,额外需要多个校验磁盘。

RAID 3: 字节级条带化 + 专用校验

将数据按字节分割,分布在多个磁盘上,同时使用一个专用磁盘存储校验信息(通过异或计算生成)。(n+1)

RAID 4: 块级条带化 + 专用校验

与 RAID 3 类似,但将数据按块分割,使用一个专用磁盘存储校验信息。

RAID 5: 分布式校验

将数据和校验信息分布在所有磁盘上,没有专用校验磁盘。每个磁盘既存储数据块,也存储校验块。(round-robin)

至少需要3个磁盘

RAID 6: 双重分布式校验

类似 RAID 5,但存储两组校验信息,能容忍最多两个磁盘同时故障。

至少需要4个磁盘

Multiple-Level RAID

10和01需要4个,50需要6个

10是stripe of mirror,先mirror再stripe

Distributed System

多个节点可以同时运行任务,提高系统的吞吐量和效率。即使部分节点发生故障,系统仍然可以继续运行。

RPC

RPC(远程过程调用)是一种分布式计算的通信机制,允许程序调用位于远程节点上的函数,就像调用本地函数一样。它屏蔽了网络通信的细节。

基本流程
  1. 客户端发起调用:
    • 客户端程序调用一个“本地代理函数”(称为 stub)。
  2. 序列化:
    • 参数被序列化(即编组,marshalling),并通过网络传输到远程服务器。
  3. 服务器处理:
    • 服务器解码参数,执行相应的远程函数,并返回结果。
  4. 结果传递:
    • 服务器将结果序列化后传回客户端,客户端反序列化后得到结果。
RPC 的优点
  • 隐藏了底层网络通信的复杂性。
  • 简化了分布式程序的开发。
RPC 的缺点
  • 性能较低:相比于本地函数调用,RPC 调用涉及网络延迟。
  • 出现失败的可能性更高:网络故障、服务器崩溃等问题。

2. Stub Compiler (桩编译器)

RPC 的实现依赖于 stub(桩)。Stub 是用于客户端和服务器之间通信的代理程序。

Stub 的作用
  1. 客户端 stub
    • 模拟远程过程,负责参数的编组(序列化)和发送。
  2. 服务器 stub
    • 接收并解码参数,调用实际的远程函数。
Stub Compiler 的功能
  • 自动生成客户端和服务器的 stub。
  • 屏蔽开发者与网络通信相关的低层细节。
  • 确保参数和返回值的正确编组和解组。

Network File System (NFS)

NFS(网络文件系统)是分布式文件系统的一种,由 Sun Microsystems 开发,允许用户通过网络访问远程主机上的文件,就像访问本地文件一样。

Statelessness (无状态性)

NFS 的设计中采用了无状态模型,这意味着服务器不维护客户端的状态信息。

无状态性的特点
  1. 每次请求独立
    • 每次客户端请求都携带完成请求所需的所有信息,例如文件句柄、偏移量等。
  2. 不依赖历史信息
    • 服务器不会记录客户端上一次的请求信息,因此即使服务器重启,客户端仍然可以继续操作。
优点
  • 简化了服务器设计:无需维护客户端状态。
  • 提高了可靠性:服务器重启后可以立即恢复服务。
缺点
  • 操作复杂性增加:无状态性要求客户端每次都发送完整信息,增加了网络负担。
  • 缺乏事务支持:无状态模型难以保证复杂操作的原子性。
posted @ 2025-06-15 22:58  lcyfrog  阅读(11)  评论(0)    收藏  举报