进程

进程组(process group)

  • 每个进程组都有一个leader进程称为进程组组长,进程组组长的pid与进程组pgid一致

会话(session)

  • 会话是若干进程组的集合

  • 一个会话最多拥有一个控制终端(tty或pts)

  • 一个会话有且只有一个前台进程组,可以有若干后台进程组

  • 会话的控制终端被前台进程组的所有进程共享

  • 每个会话有一个会话首进程,该进程的pid与sid一致

  • 当会话首进程退出时,会给该会话的所有进程发送sighup信号(kill -1 pid)

当我们使用ssh登录到一台主机时,其实就开启了一个bash进程,可以通过以下命令查看该bash进程的pid

$ echo $$
29575

创建bash进程的同时也为它创建一个会话以及一个控制终端,我们登录到主机时能够输入命令的那个就是控制终端。通过以下的命令查看会话id与终端名称等信息:

$ ps j 29575
  PPID    PID   PGID    SID TTY       TPGID STAT   UID   TIME COMMAND
 29571  29575  29575  29575 pts/2     29603 Ss       0   0:00 -bash

解释一下上面的前几列:

  • PPID:父进程id

  • PID:进程id

  • PGID:进程组id

  • SID:会话id

  • TTY:控制终端名称

  • TPGID:该session的前台进程组id

可以看出:pid等于pgid,所以bash进程是进程组29575的组长;pid等于sid,所以bash进程是会话29575的会话首进程。

接下来,我们在当前终端下起一个进程,先编写脚本 a.sh,内容如下:

#!/bin/bash

echo "a start"
/usr/bin/dockerd --config-file /etc/docker/daemon.json &
sleep 1000
echo "a end"

执行命令:

$ ./a.sh

接下来,我们在另一个终端(另一个ssh登录)下查看该session下的进程:

$ ps j -e | grep 29575
 29571  29575  29575  29575 pts/2     29575 Ss+      0   0:00 -bash
 29575  29633  29633  29575 pts/2     29575 S        0   0:00 /bin/bash ./a.sh
 29633  29634  29633  29575 pts/2     29575 Sl       0   0:00 /usr/bin/dockerd --config-file /etc/docker/daemon.json
 29633  29635  29633  29575 pts/2     29575 S        0   0:00 sleep 1000

可以看到,这几个进程共用一个控制终端(pts/2)。在这里要注意的是,a.sh在执行命令sleep 1000时,是起了一个新的进程,a.sh进程之所以没有退出是要等待sleep 1000进程结束返回。这几个进程的父子关系是:

bash
└── a.sh
    ├── dockerd
    └── sleep 1000

接下来,我们在新的终端下终止会话首进程bash进程:

$ kill -1 29575

执行该命令后,29575的bash进程的连接就断开了。我们查看会话29575中的进程情况:

$ ps j -e | grep 29575
1  29634  29633  29575 ?            -1 Sl       0   0:00 /usr/bin/dockerd --config-file /etc/docker/daemon.json

发现,a.sh进程与sleep进程不在了,但dockerd进程还在。我猜测是:会话首进程给进程组中的每个进程发送了sighup信号,a.sh进程与sleep 1000进程接收到信号后终端运行退出,而dockerd进程却忽略了该信号还继续执行。

这里我们可以手动给dockerd进程发送sighup信号,验证该进程会忽略该信号。执行以下命令,发现dockerd进程还在:

$ kill -1 29634
$ ps j -e | grep 29575
1  29634  29633  29575 ?            -1 Sl       0   0:00 /usr/bin/dockerd --config-file /etc/docker/daemon.json

同时,dockerd进程的tty变成了?,说明该进程已经没有了终端输入与输出能力;dockerd的父进程id变成1,说明该进程已被init进程管理;sid与pgid却还保持没变。

nohup vs &

后台命令符号&的意思是,子进程进入后台执行模式,父进程不需要等待子进程的返回就可以继续往后面执行。

nohup的意思是,当进程接收到sighup信号时,选择忽略,不会主动结束执行。

Reference

[1] https://www.ibm.com/developerworks/cn/linux/1702_zhangym_demo/index.html [2] https://blog.csdn.net/outofmemo/article/details/54151326

Last updated