在子进程创建和启动之前或之后放置signal.signal的区别?

问题描述 投票:0回答:1

我在使用

signal
模块管理进程行为时遇到了一个奇怪的问题。

我想在

SIGTERM
运行后从
b.py
发送
a.py
信号来终止
a.py
中的主进程和子进程。

现在我发现当

signal.signal(signal.SIGTERM, handle_signal)
放置在
__main__
入口点之前时,子进程不会按预期终止。他们还在奔跑。

但是,如果我将

signal.signal(signal.SIGTERM, handle_signal)
放在子进程启动之后,那么当
a.py
收到来自
SIGTERM
b.py
信号时,子进程可以按预期终止。

a.py
import multiprocessing
import os
import signal
import time


def process1():
    while True:
        print("the child process is running")
        time.sleep(1)


def handle_signal(signum, frame):
    print("signal received:", signum, "pid:", os.getpid())


# register signal
signal.signal(signal.SIGTERM, handle_signal)  # place here 1
if "__main__" == __name__:
    a = multiprocessing.Process(target=process1)
    a.daemon = True
    a.start()

    # signal.signal(signal.SIGTERM, handle_signal)  # place here 2

    child_pid = a.pid
    parent_pid = os.getpid()

    parent_pid_group = os.getpgid(parent_pid)

    with open("./crawler.pid", "w") as f:
        f.write(str(parent_pid_group))

    a.join()

    print("Parent id:", parent_pid)
    print("Child id", child_pid)
    print("all terminated!")
b.py
import os
import signal

with open("./crawler.pid", "r") as f:
    try:
        pid = int(f.read())
        os.killpg(pid, signal.SIGTERM)
        print("Signal sent successfully to process", pid)
    except Exception as e:
        print("Error sending signal:", e)

错误的输出 - 信号在子进程启动之前注册:

╰─ python a.py
the child process is running
the child process is running
the child process is running
the child process is running
the child process is running
signal received: 15 pid: 1379
signal received: 15 pid: 1380
the child process is running
the child process is running
the child process is running
the child process is running
^CTraceback (most recent call last):
  File "a.py", line 34, in <module>
    a.join()
  File "/usr/lib/python3.8/multiprocessing/process.py", line 149, in join
    res = self._popen.wait(timeout)
  File "/usr/lib/python3.8/multiprocessing/popen_fork.py", line 47, in wait
    return self.poll(os.WNOHANG if timeout == 0.0 else 0)
  File "/usr/lib/python3.8/multiprocessing/popen_fork.py", line 27, in poll
    pid, sts = os.waitpid(self.pid, flag)
KeyboardInterrupt
signal received: 15 pid: 1380
Process Process-1:
Traceback (most recent call last):
  File "/usr/lib/python3.8/multiprocessing/process.py", line 315, in _bootstrap
    self.run()
  File "/usr/lib/python3.8/multiprocessing/process.py", line 108, in run
    self._target(*self._args, **self._kwargs)
  File "a.py", line 10, in process1
    time.sleep(1)
KeyboardInterrupt

----------------------
╰─ python b.py 
Signal sent successfully to process 1379

正确的输出 - 信号在子进程启动后注册:

╰─ python a.py
the child process is running
the child process is running
the child process is running
signal received: 15 pid: 1961
Parent id: 1961
Child id 1962
all terminated!

---------------------
╰─ python b.py 
Signal sent successfully to process 1961

这是python机制还是操作系统设计?

python signals
1个回答
0
投票

这是python机制还是操作系统设计?

是操作系统设计。例如,类似的 C 程序也会发生同样的情况。

在每种情况下,子进程

multiprocessing.Process
都会在分叉时继承其父进程的信号处理。

在第一种情况下,该配置是您的喋喋不休的信号处理程序。这就是为什么子级和父级都报告接收到信号 15。当传递 SIGTERM 时,每个都运行处理程序,然后恢复其循环(子级)或其阻塞

join()
(父级)。

在第二种情况下,该配置是默认的,SIG_DFL。父进程在子进程被分叉后安装聊天处理程序,子进程被发送到进程组的信号终止,而父进程只是报告它。

© www.soinside.com 2019 - 2024. All rights reserved.