父进程被kill后,孤儿进程向屏幕异常输出数据,command+c也没用,有图有代码,什么情况?

a.py

import multiprocessing
import os
import signal
import time

child_processes = []

def process1():
    while True:
        print(f"子进程运行中,其父pid是:{os.getpgid(os.getppid())}")
        time.sleep(1)
if "__main__" == __name__:
    a = multiprocessing.Process(target=process1)
    a.daemon = True
    a.start()
    parent_pid = os.getpgid(os.getpid())
    with open("/var/run/crawler.pid", 'w') as f:
        f.write(str(os.getpid()))
    a.join()

b.py

import os
import signal

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

image.png

阅读 509
avatarAI BotBETA

当父进程被 kill 后,孤儿进程确实可能会继续运行并向屏幕输出数据。这是因为孤儿进程是已经被其父进程终止,但还没有被 init 进程(在 Unix 和 Linux 系统中)或 Taskmgr(在 Windows 系统中)收养的进程。孤儿进程会继续运行,直到它自己也终止或被其他进程终止。

在你的代码中,你启动了一个守护进程(daemon process)a,并将其设置为 True。守护进程在主程序结束后会自动终止,但由于 a.join() 会阻塞主进程,直到 a 进程结束,因此这里的守护进程实际上并不会在主程序结束后立即终止。然而,如果你手动 kill 了父进程,a 进程就会成为孤儿进程。

要解决这个问题,你可以考虑以下几种方法:

  1. 在父进程中捕获 SIGTERM 信号:你可以在父进程中捕获 SIGTERM 信号,并在接收到该信号时,先正常终止子进程,然后再让父进程自己终止。这样,即使父进程被 kill,子进程也会先被正常终止,不会成为孤儿进程。
  2. 使用 multiprocessing.Poolconcurrent.futures.ProcessPoolExecutor:这些高级 API 在创建子进程时,会自动处理孤儿进程的问题。当父进程结束时,它们会自动等待并终止所有子进程。
  3. 使用 os.killpg() 发送信号给进程组:你可以使用 os.getpgid() 获取父进程的进程组 ID,然后使用 os.killpg() 发送信号给整个进程组,包括子进程。这样,即使父进程被 kill,子进程也会接收到信号并被终止。

以下是使用第一种方法的示例代码:

import multiprocessing
import os
import signal
import time

child_processes = []

def process1():
    while True:
        print(f"子进程运行中,其父pid是:{os.getpgid(os.getppid())}")
        time.sleep(1)

def handle_sigterm(signum, frame):
    for p in child_processes:
        p.terminate()
    exit(0)

if "__main__" == __name__:
    signal.signal(signal.SIGTERM, handle_sigterm)

    a = multiprocessing.Process(target=process1)
    a.daemon = True
    a.start()
    child_processes.append(a)

    parent_pid = os.getpgid(os.getpid())
    with open("/var/run/crawler.pid", 'w') as f:
        f.write(str(os.getpid()))

    a.join()

在这个示例中,我们定义了一个 handle_sigterm 函数来处理 SIGTERM 信号。当父进程接收到 SIGTERM 信号时,该函数会终止子进程,并让父进程退出。这样,即使父进程被 kill,子进程也会被正常终止,不会成为孤儿进程。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进