Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

入学诊断

24 道题,覆盖命令行、Shell、系统编程、计算机系统、内核、网络六个面。不要查资料,20 分钟做完。目的不是考倒你,而是判断从哪条路线开始、哪些章可以跳。

A 组 · 命令行(4 题)

A1. 一条命令列出当前目录下所有 .log 文件,按大小从大到小,只显示前 5 个,并带人类可读的大小。

A2. cmd > out.txt 2>&1 与 cmd 2>&1 > out.txt 的区别是什么?

A3. 解释 find . -name '*.c' -print0 | xargs -0 grep -l 'TODO' 中两个 -0 的作用。如果去掉会怎样?

A4. chmod 4755 ./tool 与 chmod 755 ./tool 的安全差异是什么?现代 Linux 上更推荐的替代方案是什么?

B 组 · Shell(3 题)

B1. 下面脚本在 curl 失败时会不会退出?为什么?

#!/bin/bash
set -e
curl -fsS https://example.com/data > data.json
echo "downloaded"

B2. 写一行 Bash,把变量 $1 中所有空格替换成下划线;再写一行,把路径的扩展名去掉。

B3. trap 'rm -f "$tmp"' EXIT INT TERM 中,为什么 EXIT 和 INT 都要写?只写 EXIT 会漏掉什么?

C 组 · 系统编程(5 题)

C1. read(fd, buf, 4096) 返回 1024 代表什么?返回 0 代表什么?返回 -1 且 errno == EINTR 时应该怎么做?

C2. open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644) 中 0644 受 umask 影响吗?如果想让文件最终权限确定是 0644,应该怎么做?

C3. fork() 之后,父进程和子进程谁先运行?fork() 返回值在两边分别是什么?vfork() 为什么危险?

C4. 写一个正确的 pthread 条件变量等待循环,说明为什么必须用 while 而不是 if。

C5. write(fd, buf, n) 返回 n 是否意味着数据已经落盘?fsync()、fdatasync()、O_SYNC 各保证什么?

D 组 · 计算机系统(4 题)

D1. -1 的 32 位补码是什么?(unsigned)-1 与 INT_MAX + 1 在 C 里分别是什么行为(有符号溢出 vs 无符号回绕)?

D2. 解释 x86-64 下 call 指令对 %rsp 和返回地址做了什么;leave 与 ret 各做什么。

D3. 一个 64 位虚拟地址,4 KiB 页,四级页表各 9 位,页内偏移多少位?一级页表项覆盖多大地址范围?

D4. 两个线程同时执行 counter++(counter 是 int 全局变量),为什么可能丢失更新?给出两种修复方式并说明代价。

E 组 · 内核(4 题)

E1. 用户态调用 getpid() 时,CPU 特权级如何变化?syscall 指令与 int 0x80 的主要区别是什么?

E2. task_struct、thread_info、内核栈三者在 x86-64 上是什么关系?

E3. malloc(1GB) 成功返回是否意味着 1 GB 物理内存已经分配?mmap 之后第一次写会发生什么?

E4. 自旋锁和互斥锁的核心区别是什么?为什么自旋锁的临界区里不能睡眠?

F 组 · 网络(4 题)

F1. 从 192.168.1.10:54321 访问 10.0.0.5:443,写出 TCP 三次握手的四个关键报文(SYN、SYN-ACK、ACK)的源/目的地址与端口,以及 seq/ack 的变化。

F2. listen(fd, 128) 的 128 在现代 Linux 上对应哪个队列?队列满了以后内核默认怎么处理?ss -lnt 的 Send-Q/Recv-Q 分别表示什么?

F3. epoll 的水平触发(LT)与边缘触发(ET)区别是什么?ET 模式下为什么必须把 fd 设为非阻塞,并且一次 read 要读到 EAGAIN?

F4. 一台服务器 8 核、16 GB 内存,要支撑 100 万条空闲 TCP 连接,最可能先撞到哪些限制?给出至少四个可调项与对应命令。

评分与路线建议

得分判断建议起点
0–8命令行与系统基础薄弱路线 A,从 0.1 开始;第 1 篇只读 1.1/1.2/1.6
9–15会用但说不清机制路线 B,从 1.2 开始;第 0 篇快速过 0.2–0.6
16–20系统编程有经验,内核/网络零散路线 B 后半 + 路线 C;从 2.1 与 3.1 并行
21–24基础扎实,缺的是路径与证据路线 C;直接读第 3/4 篇,项目选 A1 或 C1

答案与简要解释

题答案关键点
A1ls -lhS *.log | head -5-S 按大小、-h 人类可读;ls 对无匹配会报错,严格写法用 find
A2前者把 stdout 和 stderr 都重定向到文件;后者先复制 stderr 到当前 stdout(终端),再把 stdout 指向文件重定向从左到右求值
A3-print0/-0 用 NUL 分隔,避免文件名含空格/换行被拆开;去掉会把空格当分隔符xargs 默认按空白分词
A44755 是 setuid root,任何用户执行都以 root 运行;现代用 capability(如 cap_net_bind_service)或 systemd 的 User=/AmbientCapabilities=最小权限
B1会退出(curl -f 失败返回非零,set -e 生效);但 curl 在 if/&&/|| 里时不退出set -e 有语境例外
B2${1// /_};${path%.*}(去掉最后一个 . 及之后)参数展开
B3EXIT 覆盖正常退出与 exit;INT/TERM 覆盖被信号杀死的情况(默认信号处理不会触发 EXIT,除非 trap 后 exit)清理要覆盖所有退出路径
C1短读,读到 1024 字节;0 是 EOF;EINTR 应重试(检查 errno,重新调用)短读/EOF/中断
C2受影响;umask 会清掉位。要确定权限,先 umask(0) 或用 fchmod()open 的 mode 不是最终权限
C3不确定,由调度器决定;父进程得到子 PID,子进程得到 0;vfork 共享地址空间,子进程不能 return/修改数据,必须 _exit 或 execfork 语义
C4while (!ready) pthread_cond_wait(&cv, &m);;if 会被虚假唤醒和多个唤醒绕过条件变量必须循环
C5不意味着落盘,只到 page cache;fsync 刷数据+元数据,fdatasync 只刷数据(及必要元数据),O_SYNC 每次写同步持久化语义
D132 个 1;有符号溢出是未定义行为(UB),无符号是模 2^32 回绕UB 与回绕
D2call 把返回地址压栈并跳转;leave 等价 mov %rbp,%rsp; pop %rbp;ret 弹出返回地址并跳转栈帧
D3偏移 12 位;每级 9 位,一级页表项覆盖 2^(9+9+9+12)=2^39=512 GiB页表位数
D4counter++ 读-改-写非原子;用互斥锁或 atomic_fetch_add;锁有竞争/阻塞成本,原子操作依赖 CAS/缓存一致性数据竞争
E1用户态 → 内核态(ring 3 → ring 0);syscall 是 x86-64 快速入口,int 0x80 是 32 位中断门,后者更慢且 ABI 不同特权级切换
E2task_struct 是进程描述符;x86-64 上 thread_info 在 task_struct 内(不再放内核栈底);内核栈是独立 THREAD_SIZE 区域结构关系
E3不意味着;malloc 只拿到虚拟地址,首次写触发缺页,内核才分配物理页/零页延迟分配
E4自旋锁忙等、适合极短临界区且不可睡眠;互斥锁睡眠等待;自旋锁持有期间睡眠会导致死锁/浪费 CPU(单核更严重)睡眠与原子上下文
F1SYN: 10.0.0.5:443 → 192.168.1.10:54321, seq=x;SYN-ACK: 反向, seq=y, ack=x+1;ACK: 正向, seq=x+1, ack=y+1三次握手
F2accept 队列(accept queue)与 SYN 队列(syn queue);tcp_abort_on_overflow=0 时默认丢弃/忽略 ACK;ss -lnt 的 Send-Q 是 backlog 上限,Recv-Q 是当前已完成握手等待 accept 的连接数两个队列
F3LT 只要可读就持续通知;ET 只在状态变化时通知一次。ET 必须非阻塞并读到 EAGAIN,否则会漏事件/阻塞epoll 语义
F4fd 上限(ulimit -n/fs.file-max)、端口范围(ip_local_port_range)、内存(tcp_mem、sk_buff)、conntrack 表(nf_conntrack_max)、backlog(somaxconn)、epoll 实例与内核对象开销百万连接

做完后把错题对应的章节标在路线图上;错 3 题以上的板块,从该板块的第一章开始读。