在UNIX环境的高级编程部分9.6中,我们可以阅读:
每当我们按下终端的中断键(通常是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信号后,每个进程都应接收信号并使用处理程序处理它 . 可悲的是,事实并非如此:
-
如果我将信号发送给进程组负责人(在这种情况下为pid 9702),所有进程都将终止,但我只能看到进程组负责人调用信号处理函数(只有一个文件被创建为处理程序调用执行路径)
-
如果我将信号发送到不是进程组组长的进程,则进程将退出,处理信号,来自同一管道(进程组)的进程也将被"silently"终止 .
$ 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
我想理解为什么这里的行为与书中描述的内容不一致(属于同一进程组的所有进程在向其中任何一个发送信号时终止) . 特别是如何将信号传递给多个进程,而不是所有信号处理程序都被调用 . 谢谢你的解释 .
1 回答
看起来我想通了 . 我的理解是CTRL-C只是将SIGINT信号发送给流程组织领导者,但看起来这样更复杂,shell将负责向进程组中的每个进程发送信号 .
在我的测试中,为什么信号处理程序只被调用一次的原因是其他进程正确退出 . 在调用 proc1 | proc2 | proc3 并查杀后,说proc1,它处理信号,proc2和proc在输入关闭时退出 . 在for循环之后添加测试sleeps()表明如果我杀死proc1剩余的进程仍然存活 .