Linux 进程组(process group)和会话(session)

进程组(process group)

进程组简单来说就是一组进程,他们有相同的进程组 ID,可以向一个进程组里的所有
进程发送信号。一般使用管道可以创建一个进程组,比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ cat | grep abc &
[1] 9761 9762
[1] + 9761 suspended (tty input) cat |
9762 suspended (tty input) grep --color=auto --exclude-dir={.bzr,CVS,.git,.hg,.svn} abc
$ ps -o pid,ppid,pgrp,session,comm
PID PPID PGRP SESS COMMAND
8663 3198 8663 8663 zsh
9761 8663 9761 8663 cat
9762 8663 9761 8663 grep
9800 8663 9800 8663 ps
$ kill -9 -9761
[1] + 9761 killed cat |
9762 killed grep --color=auto --exclude-dir={.bzr,CVS,.git,.hg,.svn} abc
$ ps -o pid,ppid,pgrp,session,comm
PID PPID PGRP SESS COMMAND
8663 3198 8663 8663 zsh
9844 8663 9844 8663 ps

可以看到后台进程里catgrep有相同的进程组号(PGRP),都是 9761。同时 9761
也是cat的进程号(PID),这并不是巧合,一般第一个进程的进程号会作为这一组进
程的组 ID。也可以看到向一个进程组发送的方法,就是在进程组 ID 前加负号。
kill之后整个进程组里的进程都被结束了。

进程组会有一个进程组长(process group leader),其进程 ID 即为这个进程组的组
ID,上面的例子中即 9761 号进程。

除了管道,进程替换也可以产生进程组。

会话(session)

一般情况下,一个 shell 窗口会打开一个会话,在这个 shell 里执行的所有命令都
属于这个会话。每个会话有一个组长(session leader),如果你用的是bash,那么
组长就很可能是这个进程,而会话 ID 也就是这个进程的 ID。

但一个程序也可以通过调用setsid()函数(还有一个setsid命令)来创建一个新
的会话,调用这个函数的程序不能是进程组长(process group leader),如果是则会
出错。如果调用进程是一个进程组长,可以先调用fork()函数,退出父进程,在子
进程中调用setsid()

在调用setsid()函数之后,调用进程会成为新会话和新进程组里的唯一进程。自然
也就成为了组长。

为什么进程组长(process group leader)不能创建会话(session)?

即,为什么进程组长不能调用setsid()

进程组 ID 是进程组长的 PID,会话 ID 是会话 ID 是会话组长的 PID。若调用
setsid()成功,则三个进程组 ID、会话 ID 和 PID 应该是相同的。

但是,对于进程组长来说,进程组 ID 已经和 PID 相同了,如果它被允许调用
setsid()的话,它的进程组 ID 会保持不变,以至于:

  • 进程组长属于新的会话;
  • 老的进程组成员属于旧的会话。

这样情况变成了一个进程组的成员属于不同的会话。POSIX 想要禁止这种情况的发生。

References

why group leader cannot able create the session in Linux

0%