使用了这么多年的 Ubuntu, 自以为 Linux 下进程的概念已经很熟悉了, 然而发现进程组(Process Group)和会话(Session)两个概念日常并不会接触很多, 平时也没有注意, 导致今天遇到一个问题还想了半天才想明白.
看了一些讲进程控制的书和文章, 感觉都比较老了, 不少都还在讲 double fork 的原理及意义, 而现实是 systemd 已经接管了几乎整个 Linux 世界, double fork 这种东西真的不应该存在了, 至少在新的程序中不应该再使用了, 所以有了这篇文章.
引子--问题
我们知道在命令行运行的前台命令, 可以随时通过 Ctrl-C 关闭掉. 原理很简单, 当我们按下 Ctrl-C 的时候, shell 进程会向前台进程发送一个 SIGINT 信号, 进程收到 SIGINT 的默认操作就是退出. 按照这个思路出发, 在 fork 之后, 如果按下 Ctrl-C 应该只有主进程会关闭, 而子进程应该继续运行, 实际上并不是这样的, 两个进程都收到了 SIGINT 信号.
import os import sys import time def child(): while True: try: sys.stdout.write("child process\n") sys.stdout.flush() time.sleep(5) except KeyboardInterrupt: sys.stdout.write("child sigint\n") sys.stdout.flush() sys.exit() def main(): while True: try: sys.stdout.write("main process\n") sys.stdout.flush() time.sleep(4) except KeyboardInterrupt: sys.stdout.write("main sigint\n") sys.stdout.flush() sys.exit() pid = os.fork() if pid != 0: main() else: child()
当我们按下 Ctrl-C 的时候
main process child process main process child process ^Cchild sigint main sigint
也就是说上述说法并不是完全正确的. 实际上, SIGINT 并不只会发送给前台进程, 而是发送给前台进程组中的每一个进程. 那么什么是进程组呢?