Kill Child Process if Parent is killed in Python

Question:

I’m spawning 5 different processes from a python script, like this:

p = multiprocessing.Process(target=some_method,args=(arg,))
p.start()

My problem is, when, somehow the parent process (the main script) gets killed, the child processes keeps on running.

Is there a way to kill child processes, which are spawned like this, when the parent gets killed ?

EDIT:
I’m trying this:

p = multiprocessing.Process(target=client.start,args=(self.query_interval,))
p.start()
atexit.register(p.terminate)

But this doesnt seem to be working

Asked By: Saurabh Verma

||

Answers:

The child is not notified of the death of its parent, it only works the other way.

However, when a process dies, all its file descriptors are closed. And the other end of a pipe is notified about this, if it selects the pipe for reading.

So your parent can create a pipe before spawning the process (or in fact, you can just set up stdin to be a pipe), and the child can select that for reading. It will report ready for reading when the parent end is closed. This requires your child to run a main loop, or at least make regular calls to select. If you don’t want that, you’ll need some manager process to do it, but then when that one is killed, things break again.

Answered By: Bas Wijnen

I’ve encounter the same problem myself, I’ve got the following solution:

before calling p.start(), you may set p.daemon=True. Then as mentioned here python.org multiprocessing

When a process exits, it attempts to terminate all of its daemonic child processes.

Answered By: flyingfoxlee

If you have access to the parent pid you can use something like this

import os
import sys
import psutil


def kill_child_proc(ppid):
    for process in psutil.process_iter():
        _ppid = process.ppid()
        if _ppid == ppid:
            _pid = process.pid
            if sys.platform == 'win32':
                process.terminate()
            else:
                os.system('kill -9 {0}'.format(_pid))

kill_child_proc(<parent_pid>)

Answered By: Rusiru Boteju

My case was using a Queue object to communicate with the child processes. For whatever reason, the daemon flag as suggested in the accepted answer does not work. Here’s a minimal example illustrating how to get the children to die gracefully in this case.

The main idea is to pause child work execution every second or so and check if the parent process is still alive. If it is not alive, we close the Queue and exit.

Note this also works if the main process is killed using SIGKILL

import ctypes, sys
import multiprocessing as mp

worker_queue = mp.Queue(maxsize=10)

# flag to communicate the parent's death to all children
alive = mp.Value(ctypes.c_bool, lock=False)
alive.value = True

def worker():
    while True:
        # fake work
        data = 99.99
        # submit finished work to parent, while checking if parent has died
        queued = False
        while not queued:
            # note here we do not block indefinitely, so we can check if parent died
            try:
                worker_queue.put(data, block=True, timeout=1.0)
                queued = True
            except: pass
            # check if parent process is alive still
            par_alive = mp.parent_process().is_alive()
            if not (par_alive and alive.value):
                # for some reason par_alive is only False for one of the children;
                # notify the others that the parent has died
                alive.value = False
                # appears we need to close the queue before sys.exit will work
                worker_queue.close()
                # for more dramatic shutdown, could try killing child process;
                # wp.current_process().kill() does not work, though you could try
                # calling os.kill directly with the child PID
                sys.exit(1)

# launch worker processes
for i in range(4):
    child = mp.Process(target=worker)
    child.start()
Answered By: Azmisov
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.