复习
本次课回答的问题
本次课主要内容
如果假设 sum.c 中的 sum++ 是如下构成:
t = atomic_fetch(sum)t++atomic_store(sum, t)那么 $k$ 个线程,输出的最小 sum 是多少?
结论有些反直觉:
sum 的最小值都是 2Verifying Sequential Consistency (VSC) is NP-Complete
课后习题难度 (3-SAT)
“加强豪华版课后习题” 😂
| VSC 的变种 | 复杂度 |
|---|---|
| 刚才的证明 (一般情况) | NP-Complete |
| 每个线程只执行 2 个操作 | NP-Complete |
| 只有 2 个变量 | NP-Complete |
| 只有 3 个线程 | NP-Complete |
| 每个读知道写者 | NP-Complete |
| 每个变量只被一个线程写入 | NP-Complete |
投机取巧的方法:
void Tworker() {
while (!feof(stdin) && scanf("%d", &x) == 1) {
long res = f(x);
lock(&lk);
sum += res;
unlock(&lk);
}
}
如果限制只有一个线程可以读,那就需要生产者-消费者了
正确率 (OJ 实时统计通过似乎只统计了编程题……)
87.5% (56/64) 的问卷表示 “没有出卖灵魂”

状态机的复制
熟悉又陌生
int open(const char *pathname, int flags);
O_CLOEXEC, O_APPEND文件描述符:一个指向操作系统内对象的 “指针”
write(3, "a", 1); write(3, "b", 1);fd = open("a.txt", O_WRONLY | O_CREAT); assert(fd > 0);
pid_t pid = fork(); assert(pid >= 0);
if (pid == 0) {
write(fd, "Hello");
} else {
write(fd, "World");
}
文件抽象的代价
概念上状态机被复制,但实际上复制后
想证明这一点?
帮助我们
fork() 可以复制状态机?
假设你实现的 NEMU 需要启动很多份
./nemu dummy.elf./nemu add.elf./nemu add-longlong.elf...int main() {
nemu_init(); // only once
while (1) {
file = get_start_request();
if ((pid = fork()) == 0) {
// bad practice: no error checking
load_file();
}
...
在实际中的应用
要是我们总是能 “试一试”,试错了还能回到过去就好了
那就用 fork() 做个快照吧

fork(): UNIX 时代的遗产fork + execve
在操作系统的演化过程中,为进程增加了更多的东西
int posix_spawn(pid_t *pid, char *path,
posix_spawn_file_actions_t *file_actions,
posix_spawnattr_t *attrp,
char * argv[], char * envp[]);
参数
pid: 返回的进程号path: 程序 (重置的状态机)file_actions: open, close, dupattrp: 信号、进程组等信息argv, envp: 同 execvefork() in the Roadfork() 的七宗罪
但 fork() 是魔法啊:这引起了更多的思考
本次课回答的问题
Take-away messages