进程属于一个进程组,进程组属于一个会话,会话可以有也可以没有控制终端.
进程组进程组是一个或者多个进程的集合,通常与同一作业相关联,可以接收同一终端的各种信号.
每个进程组有一个组长进程,标识为进程组ID等于进程ID.
进程组的存在与组长进程是否终止无关.
会话会话是一个或者多个进程组的集合.
会话可以有一个控制终端.
建立与终端连接的会话首进程称为控制进程(通常为登录shell).
会话ID即为会话首进程ID.
如果会话有控制终端,则他有一个前台进程组,剩下的为后台进程组.
键入控制终端的信号,会发送给前台进程组的所有进程.
如果终端接口检查到网络断开连接,会发送SIGHUP挂断信号到控制进程(会话首进程).
作业控制允许终端启动多个作业(进程组),并控制作业在前台后台间的切换.
终端特殊字符
(1) 中断字符(DELETE或Ctrl+C) 产生SIGINT
(2) 退出字符(Ctrl+\) 产生SIGQUIT
(3) 挂起字符(Ctrl+Z) 产生SIGTSTP
以上三个特殊字符将产生相应的信号发送给前台进程组的所有进程,后台进程组不受影响.
后台进程组试图读终端,作业控制将发送信号SIGTTIN,暂时停止后台作业.
后台进程组试图写终端,作业控制将发送信号SIGTTOU,暂时停止后台作业.(可选)
以上两种情况可通过tcsetpgrp把后台进程组置为前台进程组,并将发送继续信号SIGCONT,继续读写控制终端.
僵死进程先于父进程终止,且父进程没有进行善后处理(wait/waitpid),该进程将变为僵死进程.
孤儿进程父进程终止的进程叫孤儿进程,由init进程接管.
孤儿进程组该组中的每个成员的父进程要么是该组的一个成员,要么不是该组所属会话的成员.
不是孤儿进程组的条件是,该组中有一个进程,其父进程属于同一会话的另一个组中.
SIGHUP以下三种情况,kernel会送SIGHUP
(1) 终端关闭时,该信号被发送到会话首进程.
(2) 会话首进程退出时,该信号被发送到该会话中前台进程组的所有进程.(
不发送给后台进程组)
(3) 向孤儿进程组中的处于停止状态(收到SIGSTOP或SIGTSTP信号)的孤儿进程先发SIGHUP,再发送SIGCONT.
Bash如果会话首进程是bash,bash在收到SIGHUP后,先给jobs列表中进程发送SIGHUP,然后自己退出.
The shell exits by default upon receipt of a
SIGHUP
.
Before exiting, an interactive shell resends the
SIGHUP
to
all jobs, running or stopped.
Stopped jobs are sent
SIGCONT
to ensure that they receive
the
SIGHUP
当首进程bash收到SIGHUP信号时:
(1) 前台进程组将收到两次SIGHUP信号,一次为bash发送,一次为bash退出后kenerl发送.
(2) jobs中的后台进程组收到一次SIGHUP信号,为bash发送,内核不会给后台进程发送该信号.
注:jobs中的后台进程组指 & 执行的后台进程组,而且没有从jobs列表中删除.
disown可以删除jobs列表中的进程.
测试代码 (bash环境下)
#include <stdio.h>
#include <fcntl.h>
#include <signal.h>
char buf[] = "sighup\n";
int fd;
void fun(int sig)
{
signal(SIGHUP, fun);
write(fd, buf, sizeof(buf));
}
int main(int argc, char **argv)
{
fd = open("/home/lieyuan/a.log", O_RDWR | O_CREAT | O_TRUNC, 0755);
signal(SIGHUP, fun);
while (1)
pause();
close(fd);
return 0;
}
|
1. 命令: ./a.out
操作: 关闭终端
结果: 打印两次 "sighup"
原因: 终端关闭,会话首进程bash收到SIGHUP信号,会给前后台进程发送SIGHUP,然后会话首进程bash退出,内核又会再次发送SIGHUP给前台进程组的进程.
2. 命令: ./a.out
操作: kill -9 bash
结果: 打印一次 "sighup" (kernel发送)
原因: 会话首进程退出时,内核发送SIGHUP到该会话中前台进程组的所有进程.
3. 命令: ./a.out &
操作: 关闭终端
结果: 打印一次 "sighup" (bash发送)
原因: 终端关闭,会话首进程bash收到SIGHUP信号,会给前后台进程发送SIGHUP.内核不会给后台进程组发送.
4. 命令: ./a.out &
操作: kill -9 bash
结果: 无输出
原因: bash只有收到SIGHUP信号才会给后台进程组发送SIGHUP信号,内核也不会给后台进程组发送.
5. 命令: ./a.out & disown
操作: 关闭终端
结果: 无输出
原因: 虽然为后台进程,但是disown已经从jobs中删除,所以不会收到SIGHUP信号,内核也不会给后台进程组发送.
6. 命令: ./a.out Ctrl+Z disown
操作: 关闭终端 或者 kill -9 bash
结果: 打印一次 "sighup" (kernel发送)
原因: 进程处于后台停止状态(SIGTSTP),且从jobs中删除,杀死bash之后,成为孤儿进程,kernel会先发送SIGHUP信号,然后发送SIGCONT信号.
重点: 会话首进程和kernel都可以向会话中的进程组发送SIGHUP信号,注意区别.作业操作命令bg fg jobs kill wait disown suspend
PROCESS STATE CODES (ps)
Here are the different values that the s, stat and state output specifiers (header "STAT" or "S") will display to
describe the state of a process.
D Uninterruptible sleep (usually IO)
R Running or runnable (on run queue)
S Interruptible sleep (waiting for an event to complete)
T Stopped, either by a job control signal or because it is being traced.
W paging (not valid since the 2.6.xx kernel)
X dead (should never be seen)
Z Defunct ("zombie") process, terminated but not reaped by its parent.
For BSD formats and when the stat keyword is used, additional characters may be displayed:
< high-priority (not nice to other users)
N low-priority (nice to other users)
L has pages locked into memory (for real-time and custom IO)
s is a session leader
l is multi-threaded (using CLONE_THREAD, like NPTL pthreads do)
+ is in the foreground process group