2016-09-26 148 views
2

在UNIX环境中高级编程的第9.6节,我们可以读到:shell/kernel如何处理信号发送到同一进程组中的进程?

当我们按下终端的中断键(通常是DELETE或Control-C),中断信号被发送到所有进程前台进程组。

我写超级简单的Python脚本,处理SIGINT信号和比较结果做了一个简单的测试:

#!/usr/bin/python3 

import os 
import sys 
import signal 

def handler(signum, frame): 
    p = os.getpid() 
    with open(str(p), 'w+') as fh: 
     fh.write("Received signal at pid: {0}".format(os.getpid())) 
    raise SystemError() 


def main(): 
    signal.signal(signal.SIGINT, handler) 
    for line in sys.stdin: 
     print("READ {0}".format(line.rstrip('\n'))) 

main() 

我只是跑它像以下:

$ ./reader.py | ./reader.py | ./reader.py 

,并确保过程在同一个过程组中:

$ ps -ae pid,ppid,pgid,sess,comm 
$ PID PPID PGID SESS COMMAND 
    9702 5930 9702 5930 reader.py 
    9703 5930 9702 5930 reader.py 
    9704 5930 9702 5930 reader.py 

我的理解是,在向任何进程发送INT信号之后,每个进程都应该接收到信号并使用处理程序处理它。 可悲的是,这种情况并非如此:

  1. 如果我将信号发送到进程组组长(PID 9702在这种情况下),所有的进程都将终止,但我只能看到进程组组长调用信号处理函数(如处理程序调用执行路径只创建一个文件)

  2. 如果我将信号发送到过程,是进程组创建者,该过程将退出,处理信号,从处理之后创建的相同管道(进程组)也将“静默”终止。

    $ ps -ao pid,ppid,pgid,sess,comm 
    PID PPID PGID SESS COMMAND 
    9842 5930 9842 5930 reader.py 
    9843 5930 9842 5930 reader.py 
    9844 5930 9842 5930 reader.py 
    
    $kill -INT 9843 
    
    $ ps -ao pid,ppid,pgid,sess,comm 
    PID PPID PGID SESS COMMAND 
    1456 1446 1456 1446 weechat 
    5893 5873 5893 5873 screen 
    5928 5902 5928 5902 screen 
    9842 5930 9842 5930 reader.py 
    

我想明白为什么这里的行为是不对准什么在书中被描述(属于同一进程组的所有进程终止在发送信号到其中的任何)。特别是信号如何传送到多个进程,但并非所有的信号处理程序都被调用。谢谢你的解释。

+0

'按终端的中断键'与通过'kill'或其他方式发送信号**不一样**。在运行可执行文件的同一终端中按“Ctrl + C”。 – Tsyvarev

+0

我知道它会使所有的过程变得复杂,但我的理解是CTRL-C只是向过程组发送信号的一种方式。 – Maro

+1

'但我的理解是CTRL-C只是一种向过程组发送信号的方式。“ - 不,你错了。它是终端的一个特性,它以特定的方式处理CTRL-C。例如,GUI应用程序不处理CTRL-C,但可以通过kill终止它们。 – Tsyvarev

回答

1

看起来像我想出来的。我的理解是,CTRL-C只会将SIGINT信号发送给进程群组领导,但看起来这更复杂,并且shell将负责发送信号给进程组中的每个进程。

在我的测试中,为什么信号处理程序被称为只有一个的原因是其他进程正在退出正确。在致电proc1 | proc2 | proc3和杀害,说proc1,它正在处理信号和proc2和proc在输入关闭时退出。在for循环之后添加测试睡眠()会显示如果杀死proc1,其余进程仍然存在。

相关问题