状态机管理:创建状态机

如果要创建状态机,我们应该提供什么样的 API?

UNIX 的答案: fork

  • 做一份状态机完整的复制 (内存、寄存器现场)

int fork();

  • 立即复制状态机 (完整的内存)
    • 复制失败返回 -1 (errno)
  • 新创建进程返回 0
  • 执行 fork 的进程返回子进程的进程号

Fork Bomb

模拟状态机需要资源

  • 只要不停地创建进程,系统还是会挂掉的
  • Don't try it (or try it in docker)
    • 你们交这个到 Online Judge 是不会挂的

代码解析: Fork Bomb

:(){:|:&};:   # 刚才的一行版本

:() {         # 格式化一下
  : | : &
}; :

fork() {      # bash: 允许冒号作为标识符……
  fork | fork &
}; fork

这次你们记住 Fork 了!

因为状态机是复制的,因此总能找到 “父子关系”

  • 因此有了进程树 (pstree)
systemd-+-ModemManager---2*[{ModemManager}]
        |-NetworkManager---2*[{NetworkManager}]
        |-accounts-daemon---2*[{accounts-daemon}]
        |-at-spi-bus-laun-+-dbus-daemon
        |                 `-3*[{at-spi-bus-laun}]
        |-at-spi2-registr---2*[{at-spi2-registr}]
        |-atd
        |-avahi-daemon---avahi-daemon
        |-colord---2*[{colord}]
        ...

理解 fork: 习题 (1)

阅读程序,写出运行结果

pid_t x = fork();
pid_t y = fork();
printf("%d %d\n", x, y);

一些重要问题

  • 到底创建了几个状态机?
  • pid 分别是多少?
    • “状态机视角” 帮助我们严格理解
    • 同样,也可以 model check!

理解 fork: 习题 (2)

阅读程序,写出运行结果

for (int i = 0; i < 2; i++) {
  fork();
  printf("Hello\n");
}

状态机视角帮助我们严格理解程序行为

  • ./a.out
  • ./a.out | cat
    • 计算机系统里没有魔法
    • (无情执行指令的) 机器永远是对的