【问题标题】:How does shell/kernel handle signals sent to processes within same process group?shell/内核如何处理发送到同一进程组内进程的信号?
【发布时间】:2016-09-26 12:57:54
【问题描述】:

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 信号后,每个进程都应该接收到信号并使用处理程序进行处理。 可悲的是,情况并非如此:

  1. 如果我将信号发送给进程组组长(在本例中为 pid 9702),所有进程将终止,但我只能看到进程组组长调用信号处理函数(只有一个文件创建为handler 调用执行路径)

  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
    

我想了解为什么这里的行为与书中描述的不一致(属于同一进程组的所有进程都会在向其中任何一个发送信号时终止)。尤其是信号如何传递给多个进程,但并非所有信号处理程序都被调用。谢谢你的解释。

【问题讨论】:

  • press the terminal’s interrupt key 与通过kill 或其他方式发送信号不同。在您运行可执行文件的同一终端中按Ctrl+C
  • 我知道它会终止所有进程,但我的理解是 CTRL-C 只是向进程组发送信号的一种方式。
  • but my understanding is CTRL-C is just a way of sending a signal to a process group. - 不,你错了。它以特定方式处理 CTRL-C 是终端的一个功能。例如,GUI 应用程序不处理 CTRL-C,但您可以通过 kill 杀死它们。

标签: linux linux-kernel signals internals


【解决方案1】:

看来我想通了。我的理解是 CTRL-C 只会将 SIGINT 信号发送给进程组负责人,但是看起来这更复杂,shell 会负责向进程组中的每个进程发送信号。

在我的测试中,仅调用一个信号处理程序的原因是其他进程正确退出。调用 proc1 | 后进程2 | proc3 并杀死,比如说 proc1,它正在处理信号,并且 proc2 和 proc 在输入关闭时退出。在 for 循环之后添加测试 sleeps() 表明如果我杀死 proc1 剩余的进程仍然是活动的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-20
    • 2016-09-01
    • 2023-03-16
    相关资源
    最近更新 更多