CS162 学習記録

Lecture 4. File & IO

POSIX idea: Everything is a File.

  1. File Sys 的抽象
    a. File: 文件系统中的一组命名数据集合,拥有一套代表数据的字节流,和表示自身的元数据(例如修改时间,权限,大小,拥有者等等)
    b. Directory:代表了一个文件地址(例如/home/lrefrain/CS162/Pintos),它的内部包括若干文件和目录

  2. 任何一个进程都有一个当前工作目录 (current working directory CWD),可以使用./来访问 CWD,../访问 CWD 的父目录

  3. I/O 调用层次

  4. High-Level File APIs


    前面带 f 前缀的基本都是 High-Level File API,这些 API 主要对流进行操作,流 (stream) 是一组拥有 position 指针(代表当前在流中的位置)的未格式化的字节序列。
    下图是一些其他的以 f 开头的文件操作 API

  5. stdin,stdout,stderr


    这三个是程序启动时默认拥有的三个文件指针,其文件描述符分别为 0, 1, 2。

  6. fseek


    不同于上述用于读写的 High-Level File APIs,fseek 的修改并不针对于 stream 的字节序列本身,而是针对于流的另一个参数 position,fseek 可以以指定方式调整 File 指针指向内容的 position 的位置,SEEK_SET 就是 position = offset,SEEK_END 是 position = length - offset,SEEK_CUR 就是 position += offset

  7. High-Level APIs 的效率提升
    用户使用时希望以字节方式读取数据,而硬盘对数据的组织方式是按块(页)的方式,数据使用方式和数据组织方式之间的差异性,会导致性能的损耗。
    考虑每次用户调用并获取一个字节的数据,而内核需要将所读取字节所在的硬盘的页整个读入到内核中并返回该字节的数据,这造成了巨量的时间浪费。
    因此内核采用了缓冲区,在用户空间的缓冲区中存储一定数量的流的信息(也即 position 所处位置的流上下文),当读取完缓冲区内所有元素后,缓冲区再一次性从硬盘中获取信息放入缓冲区。
    写数据也是类似的

  8. 文件描述符 File Descriptor
    文件描述符就是一个 int 整形,kernel 中对于每个进程都专门设有一个文件描述符和打开的文件的对应表。
    使用文件描述符的原因是,出于安全性考虑,可以让进程无法直接触碰文件,只能通过系统调用来和 kernel 沟通,以 kernel 指定形式进行文件操作。

  9. Low-High Level 转换


    可以使用途中两个函数对 FILE *和文件描述符做对换。

  10. Low-Level File APIs


    其实就是 open,read,close,write,功能也类似于带 f 前缀的,主要的区别是不带缓冲区,基本上是直接对 syscall 的封装。

  11. Fork & File Descriptor


    Fork 会复制所有的文件描述符和文件描述符表,父子进程中的文件描述符副本可以操作同一个打开文件描述符。然而在内核中对同一打开文件描述符的文件描述符副本数量是有计数器的,因此只有每个副本都调用了 close(fd) 后才会真正关闭打开文件描述符。入图,父子进程轮流操作三次文件描述符之后,打开文件描述符的 Position 变为了 300。

    一个重要的示例,复制之后 0,1,2 对应的打开文件描述符 stdin,stdout,stderr 都会被复制,这就导致同一终端的输入和输出对应到了两个进程上,这往往会出错,因此我们可以选择关闭父子进程中的某一个进程中的读入文件描述符,以达到我们期望的效果。

  12. dup & dup2


    文件描述符的复制,dup 会得到传入文件描述符的副本文件描述符,dup2 会得到指定数字的副本文件描述符,他们都指向同一个打开文件描述符。

我今天阅读了《System Design Interview》的 Chapter 1,向川皇报道。

Lecture 5.

  1. 一个在网络上的不同主机间的进程间通信例子


    使用的接口是与文件 I/O 完全相同的,因为网络设备本质上也属于一种 I/O,根据 POSIX 的一切皆文件的思路,可以使用 read(),write() 等 API 进行不同主机间的通信。
    a. server 进程通过网络套接字使用 read(),由于此时 I/O 设备没有输入,因此无法读取,阻塞 wait
    b. 中断,将从网络中的设备中传来的数据包以 DMA 形式 copy 到 kernel 中
    c. a 中的阻塞停止,读取到数据包后将数据 copy 回服务器进程中
    d. 解析请求
    e. 对硬盘文件描述符使用 read(),陷入内核
    f. 内核发送 disk request 给 disk
    g. 中断,将数据从 disk 中以 DMA 方式发送给内核
    h. e 中阻塞停止,读取数据包到服务器进程
    i. 格式化回复客户的信息
    j. 调用套接字 write 陷入内核
    k. 从 user buffer 将信息 copy 到 network buffer 中
    l. 格式化回复信息的网络包以 DMA 方式发送到网络中目的主机
    可以发现三次对网络设备和硬盘的文件操作没有本质区别,都是调用函数,通过 syscall 陷入内核,完成文件操作。只不过对应的硬件接口从网络接口变成了硬盘接口,而 kernel 很好的隐藏了这一区别,使得所有操作对于 Server Process 来说看起来都一样。

  2. IPC 方式之管道


    管道是一个存储在内存中的 queue,用于在不同的 Process 中传输信息,避免了使用文件描述符,从硬盘沟通,速度更快。
    这个 In-Memory Queue 是一个阻塞式循环队列,考虑一些常见的应用场景,如果 A 的 write 速度远超 B 的 read 速度,这会导致队列变满,而反之会导致队列变空。
    因此我们可以让 A 在 write 时,检测到 Queue 为满,就阻塞,直到 B 完成了一次 read 并给 A 发送一个 signal。让 B 在 read 的时候,检测到 Queue 为空,就阻塞,直到 A 完成了一次 write 并给 B 发送一个 signal。

    管道通信实例,上图的管道建立在父子进程之间,其中 pipe_fd[0] 用于 read,pipe_fd[1] 用于 write,由于进程 fork 会复制 pipe_fd[0/1],因此我们需要关闭用不到的文件描述符。

    如图,0,1,2 是 std 描述符,3,4 分别是 pipe_fd[0/1]
    如果关闭了 write 描述符,read 描述符会一直读取到 EOF,如果关闭了 read 描述符,write 描述符会产生 SIGPIPE 信号。

  3. 任何交流都需要协议

  4. IPC 之套接字
    套接字看起来与文件描述符无异,但是一些操作无法执行,例如 lseek。
    echo server 示例


    客户端会不断读入信息,然后发送给 serer,server 将会通过套接字回复客户端,可以看到,这里的 socket 就像一个文件描述符,只使用一个整数表示。
    这个整数代表一个五元组:

    由上图中的五元组可以唯一确定出一台网络上的主机。

  5. 服务器的服务模式


    服务器有一个监听套接字,随时监听客户发来的链接请求,等确认连接请求的合法性之后会开启一个新的连接套接字用于和客户建立连接。
    a. 不安全的服务模式

    服务器的服务进程和连接进程处于同一个进程中,当连接进程出现某种问题时,会连累服务进程也遭到破坏
    b. 安全的单线服务模式

    每次需要建立连接的时候都创建一个子进程,让子进程来处理客户需要的服务,子进程中关闭监听套接字,父进程则关闭连接套接字后,等待子进程结束后再继续监听,循环往复。优点是较为安全,缺点是只能单线程接听服务,无法多线程服务多个客户,而这对一个服务器来说往往是至关重要的。
    c. 安全的多线服务模式

    与 b 的区别是不再等待子进程运行完毕后再继续监听,而是在子进程运行的过程中继续监听并创建新的子进程。优点事可以多线程服务多个客户。
    d. 线程优化的无保护的多线服务模式

    在实际生产中,创建进程的开销过大,同时一些不需要访问内存的进程或者是生命周期相当短的进程被创建实际上是很大的浪费。因此可以考虑使用线程来替代进程,做一些微小的工作。
    这涉及到一些问题,如果有大量需要服务的请求,创建大量线程仍然会在同一时间有过量的开销,因此我们使用线程池来优化这一过程。
    在监听的开始我们就创建一些线程作为线程池,用一个队列来存储当前可以使用的线程,避免了线程的反复创建和销毁,提高了效率。同时当队列为空时,我们可以阻塞服务操作,等到队列中有闲置线程时再服务这些操作。

Lrefrain 出来更新了,鞭笞,启动!

送信先のID(2533656389)のビデオを送ってもらえませんか?

【スーパーユーザー V2】百度ドライブで共有されたファイル:CS162
リンク:百度网盘-链接不存在
抽出コード:66D1
この内容をコピーして「百度ドライブ アプリ」を開き、ファイルを取得してください

「いいね!」 1