Appearance
题目
若一个用户进程通过 read 系统调用读取一个磁盘文件中的数据,则下列关于此过程的叙述中,正确的是( )。 Ⅰ. 若该文件的数据不在内存中,则该进程进入睡眠等待状态
Ⅱ. 请求 read 系统调用会导致 CPU 从用户态切换到核心态
Ⅲ. read 系统调用的参数应包含文件的名称
错因
B
承认 Ⅰ Ⅱ 而把 Ⅲ"参数含文件名"也勾上——但 read 接受的是文件描述符 fd(一个小整数),不是文件名。文件名在 open 时使用,open 返回 fd,read 用 fd 操作。把 read 当成 open 来用是这道题最常见的混淆。
C
承认 Ⅱ Ⅲ 漏 Ⅰ——其实 read 在数据不在内存时必然会让进程睡眠等磁盘 I/O。把"read 不在内存就阻塞"当成不对的,可能是默认 OS 总是把数据预取到缓存里、read 总是命中——但即使 page cache 命中很高,第一次访问仍要等 I/O。
D
把 Ⅲ 也选了——同 B 的错。read 的参数只有 (fd, buf, count),没有文件名。
总解析
read(fd, buf, count) 的标准语义:
c
ssize_t read(int fd, void *buf, size_t count);参数:
- fd:文件描述符(前面 open 返回的)
- buf:用户空间缓冲区指针
- count:要读多少字节
没有文件名——文件名在 open 时已经解析过、转成 fd 了,read 只用 fd。
逐条核对:
| 命题 | 描述 | 判定 | 说明 |
|---|---|---|---|
| Ⅰ | 数据不在内存 → 进入睡眠 | ✓ | read 是同步阻塞调用——数据不在 page cache 时进程被挂起等磁盘 I/O,是典型的"运行 → 阻塞" |
| Ⅱ | 切换到核心态 | ✓ | 系统调用必切——trap 指令陷入内核 |
| Ⅲ | 参数含文件名 | ✗ | 参数是 fd 而非文件名——文件名在 open 时使用,read 只用 fd |
read 的工作流程:
用户进程 read(fd, buf, count)
↓ trap → 内核态 ← Ⅱ 切换
内核根据 fd 查打开文件表 → 找到 inode
↓
检查数据是否在 page cache
命中 → copy 到用户 buf → 返回
未命中 → 发起磁盘 I/O
↓
进程进入阻塞态(睡眠) ← Ⅰ 睡眠
↓
I/O 完成中断 → 唤醒进程
↓
copy 到 buf → 返回正确的是 Ⅰ Ⅱ。
最终答案是 A。