一言难尽的并发部分终于结束
我们学了什么?
threads.h
) 和阅读并发程序 (model checker)精彩的内容就此开始!
用 “状态机” 的视角重新理解进程
假想你们对 OSLab0 (amgame) 编程
int main() {
while (1) {
...
}
}
如果想
今天的程序能也能在 1950s 的计算机上运行吗?
你们太熟悉了:指令驱动的状态迁移
类似于 AbstractMachine (TRM + IOE)
嗷!操作系统 “模拟” 了其中所有进程的状态机!
这就是 “虚拟化”
所有状态机都保存在共享内存里
进程 (状态机) 管理
存储 (地址空间) 管理
文件 (数据对象) 管理
(
如果要创建状态机,我们应该提供什么样的 API?
- UNIX 的答案: fork
- 做一份状态机完整的复制 (内存、寄存器现场)
int fork();
模拟状态机需要资源
:(){:|:&};: # 刚才的一行版本
:() { # 格式化一下
: | : &
}; :
fork() { # bash: 允许冒号作为标识符……
fork | fork &
}; fork
因为状态机是复制的,因此总能找到 “父子关系”
systemd-+-accounts-daemon---2*[{accounts-daemon}]
|-agetty
|-atd
|-automount---2*[{automount}]
|-avahi-daemon---avahi-daemon
|-cron
|-dbus-daemon
|-irqbalance---{irqbalance}
|-lxcfs---7*[{lxcfs}]
...
试着拿出一张纸,写出以下程序的输出结果
pid_t pid1 = fork();
pid_t pid2 = fork();
pid_t pid3 = fork();
printf("Hello World from (%d, %d, %d)\n", pid1, pid2, pid3);
问以下程序的输出结果
#define n 2
int main() {
for (int i = 0; i < n; i++) {
fork();
printf("Hello\n");
}
}
计算机系统里没有魔法。机器永远是对的。
多线程程序的某个线程执行 fork()
,应该发生什么?
我们可能作出以下设计:
光有 fork 还不够,我们还需要能 “执行别的程序” 啊?
- UNIX 的答案: execve
- 将当前运行的状态机重置成成另一个程序的初始状态
int execve(const char *filename, char * const argv, char * const envp);
filename
的程序argv
(v) 和环境变量 envp
(e)main()
的参数!“应用程序执行的环境”
env
命令查看PATH
: 可执行文件搜索路径PWD
: 当前路径HOME
: home 目录DISPLAY
: 图形输出PS1
: shell 的提示符export
: 告诉 shell 在创建子进程时设置环境变量export ARCH=x86_64-qemu
或 export ARCH=native
AM_HOME
终于破案了PATH
可执行文件搜索路径
[pid 28369] execve("/usr/local/sbin/as", ["as", "--64", ...
[pid 28369] execve("/usr/local/bin/as", ["as", "--64", ...
[pid 28369] execve("/usr/sbin/as", ["as", "--64", ...
[pid 28369] execve("/usr/bin/as", ["as", "--64", ...
PATH
里指定的顺序$ PATH="" /usr/bin/gcc fork-demo.c
gcc: error trying to exec 'as': execvp: No such file or directory
$ PATH="/usr/bin/" gcc fork-demo.c
计算机系统里没有魔法。机器永远是对的。
有了 fork, execve 我们就能自由执行任何程序了,还缺一个销毁状态机的函数
- UNIX 的答案:
_exit
- 立即摧毁状态机
void _exit(int status)
这个简单……
exit 的几种写法 (它们是
exit(0)
- stdlib.h
中声明的 libc 函数atexit
_exit(0)
- glibc 的 syscall wrapperexit_group
” 系统调用终止整个进程 (所有线程)atexit
syscall(SYS_exit, 0)
exit
” 系统调用终止当前线程atexit
本次课内容与目标
Takeaway messages