By Fradow

一 基本概念

均用10-20字描述即可。

  1. 什么是内核(kernel),什么是外壳(shell)?
  2. 写出系统调用(syscallecall 等)的功能。
  3. 什么是数据竞争?为什么C代码中要避免数据竞争?
  4. 很多操作系统都没有关机指令,那么它是如何实现关闭计算机的?
  5. 为什么磁盘等存储设备要设计成按块读取?

二 进程、线程与地址空间

现在你想在Linux上实现 pidof 指令,可通过命令行参数传入进程名,打印拥有该进程名的所有进程号。

  1. pidofmain 函数有 argcargv 两个参数,写出其函数原型,解释它们都代表什么含义。
  2. 命令行参数传给进程后存放在什么位置?
  3. 10-20字描述如何实现 pidof
  4. 操作系统中的进程可以随时开始、中止。这对的实现有何影响?如果想让 pidof 显示(近期)历史上某个瞬间的进程列表,需要如何实现?

三 编译、链接和加载

以下是执行 ./a.out 后其进程对应的一段 pmap 输出。(回忆时编的,重点是最后一列)

1
2
3
4
5
6
7
8
9
0000000000400000    132K r-x-- a.out
0000000000602000 4K r---- a.out
0000000000603000 4K r---- a.out
0000000000604000 4K rw--- a.out
00007f8b1c000000 128K rw--- [anon]
00007f8b1c020000 256K rw--- [anon]
00007f8b1c040000 132K rw--- [stack]
00007fffedcfed00 4K r-x-- [vvar]
00007fffedcff000 4K r---- [vdso]
  1. 解释静态链接和动态链接的区别。
  2. 在输出中的每一行地址空间后写出其表示的含义。./a.out 是通过静态链接还是动态链接得到的?
  3. 若实现一个调试器,支持用一个进程调试另一个进程,需要在操作系统上做什么设计(在系统对象和系统调用上)?

四 并发编程

现有n个线程(线程号为1, 2, 3, …, n)玩石头剪刀布,每个线程创建后均执行一次 play_one_round。其中调用 play 得到每个线程的胜负结果,若平局则结果均为 TIE。请写出完整的 play 函数实现。

1
2
3
4
5
6
7
8
9
void play_one_round(int pid, int type) {
assert(type == ROCK || type == SCISSORS || type == PAPER);
int result = play(pid, type);
switch (result) {
case WIN: printf("I (%d) win!\n", pid); break;
case LOSE: printf("I (%d) win!\n", pid); break;
default: break;
}
}

以下为可以使用的线程库函数。假设互斥锁初始状态为解锁。

1
2
3
4
5
6
7
8
int mutex_lock(mutex_t *mutex);
int mutex_unlock(mutex_t *mutex);
sem_t semaphore = SEM_INIT(int value); // initialize semaphore
int sem_wait(sem_t sem, mutex_t *mutex);
int sem_post(sem_t sem, mutex_t *mutex);
int cond_wait(cond_t *cond, mutex_t *mutex);
int cond_signal(cond_t *cond, mutex_t *mutex);
int cond_broadcast(cond_t *cond, mutex_t *mutex);

五 文件系统

  1. Everything is a file. 目录是文件吗?
  2. 什么是文件描述符?写出3个返回文件描述符的系统调用名称。
  3. 解释操作系统如何区分一个文件是普通文件、流还是设备。
  4. RAID相比使用单个或多个可靠磁盘有何优点?
  5. 假如有一款内存得到普及,其容量和性能与DRAM相当,断电后数据不消失(但正在写入的内容可能会消失),这会对文件系统有何影响?可以适当展开分析。