操作系统

非常重要,但是我投入不太够,也忘得差不多了,重新系统学一遍吧。内容还是王道考研

前言

操作系统是什么?

管理整个软硬件资源,合理组织调度资源;给用户和其它软件提供接口和环境;是计算机最基本的系统软件。

.bat 批处理文件,依次执行很多命令。

操作系统四个特征

并发

多个事件在同一时间间隔内发生,宏观上同时,微观上交替发生。
并行:多个事件同时发生。

共享

互斥共享(一个时间段只允许一个进程访问)和同时共享(一个时间段,多个进程同时访问)。

虚拟

空分复用技术:一个物理实体变成若干个逻辑对映体,比如虚拟内存,认为自己独占了全部内存。
时分复用技术:虚拟处理器。(切换的够快,很多进程可以同时运行)

异步

多进程并行,你不知道具体的执行顺序。

发展

纸袋机(只能读一个纸带)->外围机(一次读多个纸带)->多道批处理系统(并发运行多个纸带)->分时操作系统(切成时间片,供多用户使用)->实时操作系统(可以对任务紧急程度安排)

运行机制

c文件->预处理编译汇编链接后->二进制代码->cpu

内核:操作系统最核心部分,最接近硬件。(docker只需要linux内核就能跑了),因此一般只有管理者可以用。

内核态用户态:管理当前状态。看能否执行内核指令

中断和异常

  • 异常:是 CPU 执行指令时检测到的同步错误或特殊条件,来自内部问题
    • Trap:有意触发的异常,让内核干事(比如调试/断点)
    • Fault:可恢复的错误,如缺页异常等。执行完成后重新执行后续指令
    • Abort:不可恢复错误,强制终止程序
  • 中断:外部硬件或软件的信号,告诉CPU优先处理某个事
    • 时钟中断:调度时候,告诉该去哪里干活了
    • I/O中断:通知CPU磁盘数据准备好了

系统调用

直接请求操作系统的服务,比如(存储分配,I/O操作,文件系统等)

如果在高级语言,一般是传入系统调用参数->执行trap指令(用户态)->执行相应的处理系统调用(核心态)->返回程序。

操作系统体系结构

典型的大内核(宏内核/单内核):Linux,UNIX,优点性能高,但是内核代码庞大冗杂
典型的微内核:Windows NT,内核少,但是需要频繁的核心态和用户态之间切换。

分层结构:类似计网分层调用,这能一层层往下调用。好处是调试很方便,扩展层方便,坏处效率低了。
模块化:一个模块负责一个工作。好处逻辑清晰,易于维护,相互调用效率高。坏处不易调试。
外核:可以直接给进程分配资源(不许你内存啥的),好处是效率明显高了,坏处是降低了一致性。

操作系统引导

主存:RAM和ROM(BIOS),ROM是自启程序。

  1. CPU从特定主存地址开始,读取指令,执行ROM中引导程序(先硬件自检,再开机)
  2. 从磁盘第一块,主引导记录读取内存,执行磁盘引导程序,扫描分区表
  3. 再从活动分区,读取分区引导记录,执行程序
  4. 再找到操作系统的初始化程序并执行,完成开机

虚拟机

有两类,我们一般用的VMware是第二类,其本质是在宿主操作系统之上再分配。这样好处是方便用迁移性很好,坏处是性能很差,每一次内核请求都要通过HostOS作为中介。

对于第一类,迁移性比较差,但是性能好,可以支持更多的硬件资源。

对于虚拟机对内核的请求,会通过虚拟机管理程序后,再根据实际情况,完成请求。对内表现完成了内核操作。

进程管理

进程

基本理解

  • 程序:是静态的,是存放在磁盘里面的可执行文件,是一系列指令集合。
  • 进程:是动态的,程序的一次执行过程(统一程序多次执行对应多个进程),是资源调度和分配的一个单位
    • 程序段(程序代码),数据段(过程中产生数据),PCB(进程控制模块,有PID,磁盘占用等)

进程的状态

PCB的state来记录状态

创建态:蒸菜被创建,os为分配资源,初始化PCB
就绪态:具备运行条件,但还没运行。可能是没有CPU资源或者没调度到
运行态:占有CPU,可以在CPU上运行
阻塞态(等待态):因为某些事不得不停止,等待被唤醒。
终止态:进程从操作系统撤销,开始回收资源,撤销PCB

组织方式:优先级队列,依次执行。

进程通信

两个进程之间产生进程交互。进程是分配系统资源的单位,因此各进程拥有的内存地址空间独立,需要通过操作系统完成通信。

共享存储

对于共享存储区,多个进程共享这一片区域。但需要保证对空间访问是互斥的,不要读写覆盖了。

消息传递

  • 直接通信: 指明要发送的进程ID给内核,内核维护一个消息队列,传递的消息都从这里通过
    • 写好消息头(发送进程ID,接收ID,长度格式),消息体
  • 间接通信:以信箱作为媒介,把消息发送到指定的信箱。接收方通过访问信箱读取
    • 这样可以多个进程往一个信箱里塞消息,也可以多个从一个接收
  • 管道通信:单向通信,内存中开辟一个序列,循环队列读和写。
    • 若要双向通信需要设置两个管道
    • 若管道写满了,则写进程被堵塞。
    • 可以有多个写或多个读(看具体实现方案)

线程

现代CPU调度的基本单位(最小单位),可以在不同的CPU里面

  • 有线程ID,线程控制模块(TCB)
  • 也具有就绪,阻塞,运行状态
  • 同一进程间不同线程共享进程资源,且切换时系统损耗比较小

实现方式

  • 用户级:手动维护线程,通过应用程序完成,在外部看起来一个进程。
    • 好处:不需要频繁请求系统调用,请求中断之类的。效率高
    • 坏处:线程被堵塞后,整个进程也会被堵塞,并发不够。且不可能在多核上运行。
  • 系统级:操作系统调度 。
    • 好处:一个线程堵塞后,别的还可以运行,并发能力强。
    • 缺点:线程切换要系统调用,管理线程麻烦。开销大
    • 多线程模型:(此时又有多种实现方式),优势缺点和上面类似
      • 一对一:一个用户线程对应一个系统线程
      • 多对一:多个用户线程对应一个系统线程
      • 多对多:多个用户线程对应多个系统线程

线程状态转化

就绪,阻塞,运行三种之间相互转化。TCB来控制,会记录线程切换时候要记录和保存的数据。

调度

由于资源有限,且事情没有办法同时处理。此时确定的某种规则来决定处理顺序。

  • 调度器:在创建新进程,进程退出,运行进程受阻,IO中断和调度时候触发
  • 闲逛进程:优先度最低,没有其他就绪进程时候就可以运行一下。

三个调度层次:高级中级低级

  • 高级调度:作业调度决定哪些作业(Job)可以进入系统,成为进程。
    • 发生频率最低,发生在从外存到内存(作业的),让进程 无->创建态->就绪态
  • 中级调度:内存调度,决定进程在内存和外存(硬盘之类的)之间的转化。
    • 发生频率中,发生在从外存到内存(进程的),完成挂起态和非挂起态直接转化
  • 低级调度:进程调度,决定哪个进程可以获取CPU资源,执行任务。
    • 发生频率高,发生在内存->CPU,就绪态->运行态转化

七状态模型,其中挂起是中级调度时候,内存不够被Swap到外存的,优化系统使用。

进程调度时机(低级调度)

  • 主动放弃:进程正常终止,异常终止,主动阻塞(等待IO)
  • 被动放弃:时间片用完,被更高优先级的插入了

由此,可以对应进程的调度方式

  • 非剥夺式调度方式:只允许进程主动放弃,直到进程终止或者主动放弃。这种比较简单,但是无法处理紧急任务,早期的批处理系统才用。
  • 剥夺调度方式:外部可以暂停或终止正在进行的进程,这样就可以比如按照时间片轮转方式进行。

那什么时候不可以进程调度?

  • 处理中断的过程中
  • 进程在操作系统内核程序临界区
    • 临界资源:一个时间段只允许一个进程使用的资源,需要互斥访问
    • 临界区:访问临界资源的那段代码
    • 可以看到,如果内核不尽快释放临界资源,那么很有可能会影响内核其它资源的工作。
  • 原子操作过程中

调度算法

Cpu利用率:忙碌时间/总时间
周转时间:作业提交到处理完成之间的时间,越小越好
带权周转时间:周转时间/实际运行时间,>=1且 越小越好
等待时间:处于等待处理时间之和,一般来说一个作业需要被CPU服务多久是固定的,调度只是影响作业/进程的等待时间
响应时间:用户从提出请求到首次得到响应的时间。
响应比:(等待时间+运行时间)/运行时间

批处理系统,一次处理一个任务或者用户

  • 先来先服务(FCFS First come First serve)
    • 按照来的顺序调度
    • 简单公平,但平均等待时间长(因为可能短的等长的)
  • 最短作业调度(SJF Shortest Job First)
    • 谁最短谁先执行。
      • 抢占式就允许正在进行的中断,交给更短的;非抢占式是结束时候才换
    • 好处:平均等待时间短
    • 坏处:1.需要知道某个作业要运行多久 2.长作业一直等待得不到调度(饥饿)
  • 高响应比优先(HRRN Highest Response Ratio Next)
    • 响应比最高的先(响应比高一般意味着被用的少)
    • 优点:兼顾长短
    • 缺点:动态计算响应比开销

后面有了分时操作系统,提出了新的方案

  • 时间片调度(RR Round Robin)
    • 每个进程固定时间,到时间就切换
    • 优点:非常公平
    • 缺点:过短导致切换花费大量时间,过长导致等待长,反应慢。无法区分优先度
  • 优先级调度(Priority Scheduling)
    • 优先级队列,谁优先级高,谁先执行。
      • 抢占式:允许中断;非抢占式:不可以中断。
      • 优先级一般系统>用户,前台>后台,更偏好I/O密集型(因为I/O和CPU可以并行)
    • 好处:灵活 坏处:优先级低的可能很难调度
  • 多级反馈调度(MFQ,multiplevel feedback queue)
    • 来的时候就最高优先级,如果时间片用完了就下一级。
    • 最高级一般时间片短一点,越往下时间片会大一些。
    • 如果一个进程长时间没有被调度,那么会提高优先级,保证会被调度到。

进程同步与互斥

进程同步:保证多个进程工作遵循一定先后顺序(防止脏读幻读之类的)
进程互斥:对于临界资源访问需要互斥进行,一段时间内只能有一个进程进行访问

进程互斥

软件实现方法:

  • 单标志法:用一个共享变量决定哪个进程可以进入临界区。在访问完临界区后,会把临界区访问权限给另一个进程。也就是说,一个进程的进入临界区权限只可以由上一个赋予
    • 问题:必须按顺序走,即使一个不需要也会轮到他。即使另一个需要也轮不到他
  • 双标执法:用flag标志每个进程是否想进入临界区,如果对方想进入就先卡着不进去。当对方不想进入就进去。(先等待再设置)
    • 问题:线程安全问题,多进程会有并发问题。
    • 修复:双标志后检查法。先设置变量,再循环等待
      • 问题:死锁
  • Peterson算法:有冲突时候让别人先来
    • 问题:活锁

硬件实现方法:

  • 中断屏蔽方法:暂时关闭 CPU 的中断响应能力,在这临界区期间不会被打断
    • 优势:简单,效率高
    • 缺点:不适用于多处理机;只适用于内核进程(因为权限很大)
  • TestAndSet:检查锁是否被使用,如果没被使用就把锁设置为true
    • 优势:简单,可以应对多处理机
    • 缺点:无法进入临界区进程就会一直循环调用,占用资源
  • Swap:记录临界区是否上锁(在old变量上),如果old为false那么重上锁,整体思路优缺点和TestAndSet差不多

锁:

  • 自旋锁:一直自旋等待
    • 好处:不需要切换进程上下文,在上锁时间短时候代价抵,效率高。适合多核不适合单核。
    • 坏处:浪费CPU,且只可以对应一个资源。

信号量:

  • 整形信号量:用一个整数变量表示某个资源的个数
  • P:申请一个资源
  • V:释放一个资源
int S = 1 ;
void wait (int S) { // wait原语(不允许中断的),进入进入区
  while (S <= 0);   // 一直循环等待(占用资源)
  S = S - 1;        // 资源足够,占用资源
}
void signal (int S) {  // signal 原语 退出区
  S = S + 1;           // 使用完资源后,在退出区释放资源
}
  • 记录形信号量:用记录形数据结构表示
    • 相比于上面的,当资源不可用时候,操作系统就会挂起,放在等待队列里面。其他线程调用 V() 时,操作系统会从等待队列中唤醒一个线程,再去执行。这样就节省了CPU资源
    • 实现方法就是记录一个资源数,每有一个就-1,当不足时候挂起放在队列里面。当唤醒时候,判断当前资源数如果是负数则唤醒一个资源。

此时,就可以也可以用信号量完成同步操作。

例如对于下图,保证同步的方法就是,对于每一个依赖关系,都添加一对信号量。比如S1S2,你可以让S1执行完成之后,才V(a)释放资源,这样S2才可以开始。于是保证了同步

生产者-消费者

生成者进程会把产品生成好放在缓冲区,消费者会去里面消耗。

显而易见,对于缓冲区的访问,各个进程必须互斥的进行。不然可能多个读同一个或者多个写同一个问题。

注意必须要先消耗empty和full资源,再去申请锁。即:实现互斥操作的P操作一定要在实现同步的P操作之后。不然可能会死锁

多生产消费者

每次需要检查两个资源,一是缓冲区是否有剩余,二是是否是自己对于的资源。

管程

为什么引入?方便使用。只能够通过特定的入口才可以访问数据,一次只允许一个线程执行内部过程

特性管程(Monitor)信号量(Semaphore)
设计目标封装共享资源,简化同步逻辑提供更底层的同步原语
互斥实现自动(编译器/语言内置锁)需手动用 P()/V() 实现
条件同步内置 wait()/signal()需用多个信号量组合实现(复杂)
易用性高(避免死锁、优先级反转{低优先级阻塞高优先级}等问题)低(容易用错,比如 P()/V() 顺序错误)
典型语言Java (synchronized+wait/notify)、C#C/C++、操作系统原语

死锁

银行家问题,吃不到饭。多个进程都在等待对方释放资源。

原因:资源有限,顺序不当

预防策略

  • 破坏互斥条件:如SPOOLing技术,把物理上独占的资源改成逻辑上共享的资源
    • 问题:很多时候没有办法破坏互斥条件
  • 破坏不剥夺条件
    • 不剥夺条件:进程所获得资源在没有使用完前,不可以强行夺走
    • 问题:实现复杂,申请保存有开销,可能导致饥饿
  • 破坏请求和保持条件:
    • 即一次申请全部想要的资源,不再对别的请求了。
    • 资源利用率低,也有可能导致一些进程饥饿

银行家算法

核心就算避免死锁。原理是,假设分配资源之后,寻找是否存在一个安全的分配序列,如果找不到,则说明当前分配不安全,就不允许分配。

  • 判断是否超过之前所要的请求,若超过就认为出错
  • 判断系统能否满足这一次要求
  • 判断分配后,是否会进入不安全状态
  • 若可以就分配,不行就不分配,让那个进程阻塞等待

死锁检测与解除

  • 检测:资源分配算法(RAG)
    • 构建分配图:(进程节点P和资源节点R连接)
    • 简化图:找出不阻塞的进程然后去除,直至无法简化。如果还有边那就说明有死锁

内存

基本知识

物理逻辑内存

物理内存:实际存在的RAM硬件地址
逻辑内存:进程看到的地址空间

地址绑定

地址绑定:逻辑地址转化为物理地址

  • 编译时绑定:程序在编译期间就绑定物理地址。
    • 问题:灵活性非常差
  • 加载时绑定:加载到内存的时候绑定地址,
    • 问题:如果程序被换出内存,地址可能变化了
  • 运行时绑定:运行时候,通过MMU动态转化为物理地址
    • 高效,动态支持(分页交换等),支持虚拟内存

地址保护

内存保护:防止进程访问其它进程或者操作系统内存

  • 方案一:基址寄存器(Base Register)和界限寄存器(Limit Register)
    • 记录起始地址和最大地址,每次访问时候判断是否合法
  • MMU(Memory Management Unit) 负责地址转换和保护。
    • 使用 页表(Page Table) 或 段表(Segment Table) 实现更精细的保护

覆盖和交换

为什么?因为早期计算机内存不足。

内存覆盖:程序划分为多个模块,按需加载到内存,同一时间只保留必要的模块。但是需要程序员手动管理,比较麻烦。

内存交换:当内存不足时候,把整个进程暂时交换到磁盘交换区(Swap),等需要的时候再换回内存,提高了多进程的并发性。现在一般也就linux用

技术演进:覆盖->交换->虚拟内存(分页/分段)->现代混合管理(Swap+分页)

内存管理

内部碎片:分配给进程的内存区域,有没有利用上的
外部碎片:由于内存分配太零散,块都太小难以利用上

连续分配

单一连续分配

内存分为系统区和用户区,且内存只有一个程序(用户进程独占)

优点:简单,没有外部碎片 缺点:只有一个进程利用率很低,有内部碎片

固定分区技术

把内存分成若干大小的分区

优点:无外部碎片 缺点:程序过大都不满足,且会有内部碎片利用率低

动态分区分配

进程装入内存时候,动态建立分区 。

优点:彻底没有内部碎片了(要多少给多少) 缺点:外部碎片很多

动态分配算法
  • 首次适应算法:第一个找到的块
  • 最佳适应算法:优先使用最小满足的
    • 问题:会留下很多很小的无法利用的块
  • 最坏适应算法:优先使用最大的
    • 问题:大进程没得用了
  • 邻近适应算法:每次从上次结束的位置去找

非连续分配

分页存储

物理内存和进程的地址空间都被划分为大小相同的页,操作系统通过页表记录页到物理页框的映射关系。

问题一:怎么找?通过偏移量找到事哪一页,然后计算页内偏移量找到。二进制的话mod直接取后面多少位就行,很方便 。每一个进程都有自己一个独立的页表,页表一般放在内存某个区域,寄存器存着可以快速找到。

快表(TLB)

由于页表放在内存中,直接访问性能下降(地址转化需要多次访存,因此加入了Cache)

要访问页的时候,先去快表查一下,没查到再去内存的页表去找,然后再去内存里面去找。这里也就有了局部性,如果你多次访问都在一个页表里面,那Cache找的就快。

两级页表

为什么需要?占用太大了。一个很小占用的进程如果维护一个很大的页表就很亏。那就相当于再给全部的页表再加一个页表,并加一个标记表示当前页块(二级页表)是否存在,如果不存在就报缺页异常,然后读取过来。

分段

把程序的逻辑地址空间分成多个段,那这个时候,逻辑地址就是<段号 ,段内偏移>

为了记录这些信息呢,系统就会维护一个段表

优点缺点
分页内存利用率高,不会有外部碎片不方便按照逻辑模块实现信息共享保护
分段很方便按照逻辑实现信息共享可能会有外部碎片,对于很长的连续空间分配很不方便

分段好处就是便于权限管理,比如这一块代码段就不可写之类的。

段页式管理

先分段,再分页

特性分段(Segmentation)分页(Paging)段页式(Seg-Paging)
内存划分按逻辑模块(可变长)按固定页(4KB等)先分段,再分页
碎片问题外部碎片严重仅内部碎片无外部碎片
硬件依赖段寄存器 + 段表MMU + 页表段寄存器 + 页表
现代应用基本淘汰主流(Linux/Windows)x86保护模式(实际被扁平化)

虚拟内存

让进程以为自己独占了整个内存。实际上有些东西,需要时候才会去调用,不常用就换下去了。

核心几个技术:请求分页,页面置换,分页存储

  • 页表机制
    • 状态位:表示页面是否在内存
    • 访问字段:记录最近被访问了几次
    • 修改位:表示页面在内存时候是否被修改过
    • 外存地址:页面在外存中存放的位置
  • 缺页中断机构:
    • 找到页表项后检查页面是否在内存中,不存在就缺页中断
    • 缺页中断处理中,需要把目标页调入内存,有必要时候换出页面
  • 地址变换机构:
    • 找到页表项检查页面是否在内存
    • 不存在就调页
    • 存在就换出页面
    • 页面调入内存后,需要修改对应表项数据

页面置换算法

  • 最佳置换算法:选择以后永远不适用或者最长实现内不再被使用
    • 问题:你怎么知道?
  • 先入先出算法FIFO:先入先出
    • 缺页率高,哪怕经常用也换出去了,性能差
  • 最近最久(LRU):最近最久没有使用的
    • 性能好,但实现难(?)开销大(?)
  • 时钟置换算法:循环队列,如果一个被用了置为1,要替换时候把1变成0,找到第一个为0的换出去
    • 优化:把修改过的先换出去

页面分配算法

  • 驻留集:给进程分配的总大小。一般小于进程总大小,过大浪费,过小频繁调度卡死了。
  • 页面分配策略(两两组合)
    • 固定分配:固定给空间不准变
      可变分配:每个开始有一定块,根据实际情况变大变小
      局部置换:缺页时候只可以从自己进程里面换
      全局置换:可以把外部的页给进程,也可以把进程的页给出去
  • 抖动现象:一个块刚换出去就要换进来。一般就是因为给的页少了
  • 何时调入页面:
    • 预留策略:进程开始运行之前,选择哪些块进去
    • 请求调页策略:发现缺页就调页
  • 从何处调页:
    • 交换区:连续存储更快 文件区:采用离散的存储方式,速度慢
    • 交换区够大就用,交换出来就放着
    • 交换区不够大就每次从文件区读,修改回去的放在交换区
  • 工作集:某短时间内,进程实际访问页面的集合。一般比驻留集比这个大一点(不然工作者呢你一直换出去换进来)

内存映射文件

用来让程序员更方便使用文件的。

特性内存映射文件(mmap)传统I/O(read/write)
数据拷贝无(直接操作页缓存)需从内核缓冲区拷贝到用户缓冲区
内存占用按需加载(缺页中断)需预先分配缓冲区
随机访问直接通过指针跳转lseek()+read()
共享性支持多进程共享需额外机制(如管道、共享内存)
适用场景大文件、频繁随机访问、共享需求小文件、简单顺序读写

文件管理

基本概念

是啥?存储在外存的命名数据集合,可以是文本程序图像,有文件名文件类型文件大小等

结构:无结构(流式文件)文本文件,有结构(记录文件)数据库文件,excel,索引文件(快速定位文件的)

存储方式:一个个块

逻辑结构

  • 无结构文件:一系列二进制流或字符流组成,成为流式文件。如Windows的txt
  • 有结构文件:由一组相似的记录,就像数据库一样。
    • 顺序文件:逻辑上顺序相连(可以是链表或者数组)
    • 索引文件:通过索引表,指到每一项的位置
    • 索引顺序文件:通过索引表,指向每一个文件位置
      • 多级索引:给索引建索引

文件目录

  • 单级目录结构
    • 所有文件放在同一个目录下,简单但容易发生命名冲突
  • 两级目录结构
    • 为每个用户创建单独目录,实现多用户
  • 树形目录结构
    • 和现代的比较像了,但是文件共享不方便
  • 无环图目录
    • 允许文件和目录被多个目录引用,分为软链接硬链接。当一个文件被引用为0就彻底被删除。
    • 好处支持了文件共享,坏处需要避免循环引用

文件的物理结构

  • 连续分配:记录起始块号和长度
    • 支持顺序访问和随机访问
    • 问题:我需要每个文件在磁盘上有一组连续的块,不方便文件扩展,碎片也多
  • 链接分配
    • 隐式链接:块之间像链表连接,目录中只标注起始和结束块
      • 方便扩展文件,不会有碎片
      • 只支持顺序访问,随机访问效率低
    • 显示链接:把文件所有的块索引全部存在一张表(文件分配表FAT中),记录下一个块和是否结束
      • 此时,要查找第几块就只需要fat表(在内存中)跳转几次之后,再去找对应的块即可,随机访问速度快了很多
      • 缺点:存储文件分配表需要一定内存
  • 索引分配
    • 为每一个文件有一个索引表,索引表内顺序
    • 支持随机访问,也很容易扩展,也需要占用一点空间
      • 如果文件太大,一个索引表不够(?)
      • 连接索引,多层索引(类似多级页表),混合索引

文件存储空间管理

  • 空闲表法:起始空闲块和空闲块数
  • 空闲链表法:记录指向下一个文件的头
  • 位示图法:用bit表示是否被分配,然后存一个大表
  • 成组链接:大块指小块

文件基本操作

  • 创建文件
    • 文件系统为新文件分配一个inode,并更新目录项
  • 打开文件
    • 检查用户是否有权限,返回一个文件描述符,便于操作
  • 读取文件
    • 根据文件描述符找到文件inode,然后定位数据块,复制到内存
  • 写入文件
    • 根据文件描述符找到文件inode,分配或更新数据块,然后再写入磁盘
  • 关闭文件
    • 操作系统刷新文件缓冲区,把数据写入磁盘
  • 删除文件
    • 删除文件目录项,释放inode和数据块

inode:index node(索引节点),每个文件或目录有唯一一个inode,记录存储了文件的元数据(文件大小,权限,所有者等),以及指向文件数据块指针。

所以inode是文件真实身份,文件名只是起一个别名,便于用户识别

文件共享

特性硬链接软链接
本质同一inode的多个文件名指向存储目标路径的独立文件
跨文件系统不支持支持
链接目标类型仅限文件文件或目录
inode号与原始文件相同独立于原始文件
目标删除后仍可访问(直到引用计数归零)链接失效(悬空)
性能更高(直接访问inode)略低(需路径解析)
创建命令(Linux)ln source targetln -s source target

文件保护

  • 口令保护
    • 加密文件,需要输入口令对比
    • 好处:开销小 坏处:不太安全
  • 加密保护:需要提供正确密码才可以正确的解密
    • 比如说给文件所有数据异或,你只有知道密码才正确解密
    • 缺点:加密解密都要一定时间
  • 访问控制:记录每个用户可以对文件有哪些操作

文件系统目录结构

虚拟文件系统

比如说你的硬盘,U盘,机械硬盘可能文件系统都不一样,此时用虚拟文件系统VFS屏蔽这些差异,可以方便的使用

挂载:文件系统挂载到操作系统中(U盘)。1.VFS中注册挂载表,2.提供函数列表 3.挂载在某个父目录下

I/O设备管理

鼠标键盘啥的

  • 机械部件:鼠标键盘显示屏,执行具体的I/O操作
  • 电子部件:CPU和I/O设备的中介,用来控制和转换输出

控制方式

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇