linux进程关系
概要
- 进程可以属于同一个进程组,多个进程组组成一个会话
- 进程组和会话只要用于实现job controller,比如bash的
ls &
,表示创建一个background进程组
示意图
--------------------------------------------------------------------------------
| ------------------------------ ----------------- |
| | pid1, pid2, ... | | pid3, pid4, ... | |
| pgrp1 | (forground) | ,pgrp2 | (backgroud) |, ... |
| | session leader <----+ | | | |
| | (who create session) | | | | |
| --------------------------|--- ----------------- |
session1 | | ^ | | |, session2(同session1, 省略)
-----------|----|------------------|-------------------------|------------------
read/write | | signal |signal |read(收到SIGTTIN, 挂起)
-------v----|------------------|-------------- |write(收到SIGTTOU, 挂起)
| --------------- ------------------- | |
| | Ctrl+C,Ctrl+ | | 连接断开SIGHUP | |<---------+
| --------------- ------------------- |
| controlling terminal |
----------------------------------------------
pgrp
- shell和systemd启动的进程,pgid和sid都是进程本身,进程启动之后,它的子进程将继承父进程的pgid和sid
- getpgid获取pgid,setpgid设置pgid
- pid等于pgid的进程,被称为pgrp leader
- 信号可以发给一个进程,或者一个进程组
- wait可以等待某个子进程,也可以等待某个进程组
session
- 多个pgrp组成一个session
- setsid()创建创建新的session, 调用setsid的进程被称为session leader; getsid()获取session id, session id就是session leader所在的pgrp的pgrp id
- 每个session可以有一个controlling terminal(tty或者pts),默认不分配tty;登录会话会自动分配tty;当有controlling terminal时,进程组分为foreground pgrp和background pgrp
- terminal相关的信号(如ctrl+C, ctrl+)会分发给foreground pgrp中的所有进程, 终端断开的SIGHUB信号会发给controlling process
- 如果session内的进程需要使用controlling terminal,直接open("/dev/tty")即可
- 可以使用tcgetpgrp获取foreground pgrp的pgid, 使用tcsetpgrp设置foreground pgrp
- 查看进程是否有controlling terminal, ps -o tpgid,如果为-1,则表示没有controlling terminal
孤儿进程组
- 当进程组中的所有进程的父进程不在该进程组所在的会话中时,该进程组被称为孤儿进程组
- 当内核发现有新的孤儿进程组产生时(一般是pgrp leader退出了),这时候内核会给该进程组内的所有进程发送SIGHUP信号(一般进程收到SIGHUP后会退出),然后发送一个SIGTCONT信号(如果进程因SIGTSTP信号stop)
- 孤儿进程组中的进程访问controlling terminal会返回EIO错误,而不是收到SIGTTIN或者SIGTTOU信号挂起
参看
- man 7 credentials
- man 2 setsid, man 2 setpgid, man 2 fork