Unix: 控制终端

jobs,fg和bg是控制进程(任务)执行的命令。jobs显示在当前shell环境下任务的状态:正在后台运行的任务,已经终止,以及被停止 (stopped)的任务。键入Control-Z,当前控制终端的前台任务会收到STOP信号从而被停止。可以使用bg命令把它放在后台继续运行。fg 命令会把后台运行的任务或被停止的任务在前台继续运行。

后台任务可能因为这些信号SIGTSTP, SIGSTOP, SIGTTIN和SIGTTOU处于被停止状态。   当一个后台进程组的一个成员试图去读它的控制终端时,这个进程组会收到SIGTTIN信号。同样,当它试 图写控制终端时,SIGTTOU信号会发出。(为何有时候消除使用setsid消除控制终端了,却依然存在呢?)

缺省情况下,这些信号会导致这些进程(任务)被停止。如果进程忽视或holding这些信号,读写会失败,但 没有信号发出。当Control-z被键入,SIGTSTP会产生并发送给前台进程组的所有进程,这就是为什么前台进程停止的原因。

-----------------------------------

想使进程丢弃控制终端,可以使用setsid调用,使得当前进程创建一个新的session和一个新的进程组,当前进程为新的session的会话头进程,新的进程组的进程组头进程。。。不过如果当前进程已经是一个进程组的头进程的话,setsid会失败。

------------------------------------

[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\n",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文件的内容为 front : sighup received
原因: sigtest是前台进程,终端关闭后,根据上面提到的第1种情况,
login shell作为session首进程,会收到SIGHUP信号然后退出,
根据第2种情况,sigtest作为前台进程,
会收到login shell发出的SIGHUP信号。
2、命令:sigtest back > tt.txt &
操作: 关闭终端
结果: tt文件的内容为 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后父进程马上退出

posted @ 2012-06-02 10:55  Jack204  阅读(2433)  评论(0编辑  收藏  举报