1.SIGHUP信号
UNIX中进程组织结构为 session (会话)包含一个前台进程组及一个或多个后台进程组,一个进程组包含多个进程。一个session可能会有一个session首进程,而一个session首进程可能会有一个控制终端。一个进程组可能会有一个进程组首进程。进程组首进程的进程ID与该进程组ID相等。这儿是可能会有,在一定情况之下是没有的。与终端交互的进程是前台进程,否则便是后台进程。
SIGHUP会在以下3种情况下被发送给相应的进程:
1、终端关闭时,该信号被发送到session首进程以及作为job提交的进程(即用 & 符号提交的进程)
2、session首进程退出时,该信号被发送到该session中的前台进程组中的每一个进程
3、若父进程退出导致进程组成为孤儿进程组,且该进程组中有进程处于停止状态(收到SIGSTOP或SIGTSTP信号),该信号会被发送到该进程组中的每一个进程。
系统对SIGHUP信号的默认处理是终止收到该信号的进程。所以若程序中没有捕捉该信号,当收到该信号时,进程就会退出。
下面观察几种因终端关闭导致进程退出的情况,在这儿进程退出是因为收到了SIGHUP信号。login shell是session首进程。
首先写一个测试程序,代码如下:
#include <stdio.h>
#include
<signal.h>
char **
args;
void exithandle(int
sig)
{
printf("%s : sighup received ",args[1
]);
}
int main(int argc,char **
argv)
{
args =
argv;
signal(SIGHUP,exithandle);
pause();
return 0
;
}
程序中捕捉SIGHUP信号后打印一条信息,pause()使程序暂停。
编译后的执行文件为sigtest。
1、命 令:sigtest front > tt.txt
操 作:关闭终端
结 果:tt.txt文件的内容为front : sighup received
原 因: sigtest是前台进程,终端关闭后,根据上面提到的第1种情况,login shell作为session首进程,会收到SIGHUP信号然后退出。根据第2种情况,sigtest作为前台进程,会收到login shell发出的SIGHUP信号。
2、命 令:sigtest back > tt.txt &
操 作:关闭终端
结 果:tt.txt文件的内容为 back : sighup received
原 因: sigtest是提交的job,根据上面提到的第1种情况,sigtest会收到SIGHUP信号。
3、命 令:写一个shell,内容为[sigtest &],然后执行该shell
操 作:关闭终端
结 果:ps -ef | grep sigtest 会看到该进程还在,tt文件为空
原 因: 执行该shell时,sigtest作为job提交,然后该shell退出,致使sigtest变成了孤儿进程,不再是当前session的job了,因此sigtest即不是session首进程也不是job,不会收到SIGHUP。同时孤儿进程属于后台进程,因此login shell退出后不会发送SIGHUP给sigtest,因为它只将该信号发送给前台进程。第3条说过若进程组变成孤儿进程组的时候,若有进程处于停止状态,也会收到SIGHUP信号,但sigtest没有处于停止状态,所以不会收到SIGHUP信号。
4、命 令:nohup sigtest > tt
操 作:关闭终端
结 果:tt文件为空
原 因: nohup可以防止进程收到SIGHUP信号
至此,我们就清楚了何种情况下终端关闭后进程会退出,何种情况下不会退出。
要想终端关闭后进程不退出有以下几种方法,均为通过shell的方式:
1、编写shell,内容如下
trap "" SIGHUP #该句的作用是屏蔽SIGHUP信号,trap可以屏蔽很多信号
sigtest
2、nohup sigtest 可以直接在命令行执行,
若想做完该操作后继续别的操作,可以 nohup sigtest &
3、编写shell,内容如下
sigtest &
其实任何将进程变为孤儿进程的方式都可以,包括fork后父进程马上退出。
2.SIGCHLD信号
子进程死后,会发送SIGCHLD信号给父进程。
一个进程在调用exit命令结束自己的生命的时候,其实它并没有真正的被销毁,而是留下一个称为僵尸进程(Zombie)的数据结构(系统调用exit,它的作用是使进程退出,但也仅仅限于将一个正常的进程变成一个僵尸进程,并不能将其完全销毁)。在Linux进程的状态中,僵尸进程 是非常特殊的一种,它已经放弃了几乎所有内存空间,没有任何可执行代码,也不能被调度,仅仅在进程列表中保留一个位置,记载该进程的退出状态等信息供其他进程收集,除此之外,僵尸进程不再占有任何内存空间。它需要它的父进程来为它收尸,如果他的父进程没安装SIGCHLD信号处理函数调用wait或waitpid()等待子进程结束,又没有显式忽略该信号,那么它就一直保持僵尸状态,如果这时父进程结束了,那么init进程自动会接手这个子进程,为它收尸,它还是能被清除的。但是如果如果父进程是一个循环,不会结束,那么子进程就会一直保持僵尸状态,这就是为什么系统中有时会有很多的僵尸进程。
2.SIGTERM信号
kill() 可以发 SIGTERM 过去;kill 命令默认也使用 SIGTERM 信号。
SIGTERM 信号的处理函数,常见的是用来清理、退出;或者程序可以忽略这个信号,以防误杀。
SIGTERM is the default signal sent to a process by the kill or killall commands. It causes the termination of a process, but unlike the SIGKILL signal, it can be caught and interpreted (or ignored) by the process. Therefore, SIGTERM is more akin to asking a process to terminate nicely, allowing cleanup and closure of files. For this reason, on many Unix systems during shutdown, init issues SIGTERM to all processes that are not essential to powering off, waits a few seconds, and then issues SIGKILL to forcibly terminate other processes to allow the computer to halt.
下面是几种常见的信号:
SIGHUP :从终端上发出的结束信号.
SIGINT :来自键盘的中断信号 ( ctrl + c ) .
SIGKILL :该信号结束接收信号的进程 .
SIGTERM:kill 命令发出 的信号.
SIGCHLD:标识子进程停止或结束的信号.
SIGSTOP:来自键盘 ( ctrl + z ) 或调试程序的停止执行信号.
http://hi.baidu.com/shiqyn/blog/item/9afa9afabce2ed8c9f514656.html