- 论坛徽章:
- 0
|
回复 #7 cjaizss 的帖子
原帖由 cjaizss 于 2007-11-25 01:14 发表
如果还不能说明问题的话
#include
#include
#include
void f(int s){printf("test\n");}
int main()
{
signal(SIGINT,s);
fork();
pause();
}
在前台运行./a.out
ctrl+c
首先,signal(SIGINT, s)是个笔误,应该是signal(SIGINT, f);
小问题,我们忽略。
现在我们cc -o ./a.out xx.c 得到了这个./a.out
好的,我们换个终端
/tmp>ps -xj
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
31875 31876 31876 31876 pts/5 1149 Ss 504 0:00 -bash
31875 32374 32374 32374 pts/6 1158 Ss 504 0:00 -bash
31876 1149 1149 31876 pts/5 1149 S+ 504 0:00 ./a.out
1149 1150 1149 31876 pts/5 1149 S+ 504 0:00 ./a.out
很显然,进程号=sid号的session的首领,就是我们的loginshell,这里就是红色标出的bash,其后的两个./a.out(进程号为别为
1149,1150)。TPGID就是前台进程组号。注意我们还没有执行ctrl+c,已经看到,bash这时候已经是前台进程组。而并非cjaizss 朋友在上一帖子说得,shell执行了read,跑到了前台。(再此,我妄解一下cjaizss 朋友的意思,原来的表述是“跑到前台”,我理解成“跑到前台进程组”,不知道是不是合适。因为终端上按下ctrl+c引发的动作是专门的对于“前台进程组”这个概念来说的。而不是说,只有某个进程获取了终端(读写)才能得到ctrl+c的动作。这个概念应该是不对的。可以想象,任一时刻,只有可能一个进程block/use在终端读写上。不知道这样把cjaizss 朋友的“前台”,置换成这里的“前台进程组”是不是有什么问题。希望cjaizss 可以进一步的交流澄清。)实际上我们看到,进程号31876,1149,1150都跑到了同一个前台进程组。只是前者进程组号是31876,后者1149(观察PGID列)。这就是登录bash,总是交互模式启动,所以才会导致后两者又新启动了一个进程组。需要说明的一点,一个进程是否能够接受到信号,和当前是否占据终端无关。当我们按下ctrl+c,终端驱动程序,就会得到前台进程组号,依次给该组的每个成员发送信号。导致的结果就是两个./a.out分别收到了SIGINT,打印出一句话。pause返回-1,pause返回-1。因为pause返回-1,因此整个main返回-1,因为bash是通过WEXITSTATUS来获取其子进程的返回值,这样-1的低8位就是$?的值,正好是0xFF(因为-1就是全bit全1的int)为255。和我们的实验一致。因为bash是个登录shell,设计成忽略SIGINT,因此,即便命令行显式的kill -2 $$仍然无法让其终止。当我们按下ctrl+c时候,并非该登录shell没有接受到SIGINT(只要它在前台进程组,就一定会接收到),而是因为它作为登录shell启动时候,已经设置了忽略了该信号。
题外话,如果
gcc -std=c99 x.c来编译,./a.out执行,那么ctrl+c后,$?应该是0。因为c99要求main没有明确的返回值,则要求返回0. |
|