obtaining pid of child process

38,289

Solution 1

Similar to @rakslice, you can use psutil:

import signal, psutil
def kill_child_processes(parent_pid, sig=signal.SIGTERM):
    try:
      parent = psutil.Process(parent_pid)
    except psutil.NoSuchProcess:
      return
    children = parent.children(recursive=True)
    for process in children:
      process.send_signal(sig)

Solution 2

Since you appear to be using Unix, you can use a quick ps command to get the details of the child processes, like I did here (this is Linux-specific):

import subprocess, os, signal

def kill_child_processes(parent_pid, sig=signal.SIGTERM):
        ps_command = subprocess.Popen("ps -o pid --ppid %d --noheaders" % parent_pid, shell=True, stdout=subprocess.PIPE)
        ps_output = ps_command.stdout.read()
        retcode = ps_command.wait()
        assert retcode == 0, "ps command returned %d" % retcode
        for pid_str in ps_output.split("\n")[:-1]:
                os.kill(int(pid_str), sig)

Solution 3

For your example you may use the subprocess package. By default it executes the command without shell (like os.system()) and provides a PID:

from subprocess import Popen
p = Popen('iostat 2 > a.txt', shell=True)
processId = p.pid
p.communicate() # to wait until the end

The Popen also provides ability to connect to standard input and output of the process.

note: before using shell=True be aware of the security considerations.

Solution 4

I think with the multiprocess module you might be out of luck since you are really forking python directly and are given that Process object instead of the process you are interested in at the bottom of the process tree.

An alternative way, but perhaps not optimal way, to get that pid is to use the psutil module to look it up using the pid obtained from your Process object. Psutil, however, is system dependent and will need to be installed separately on each of your target platforms.

Note: I'm not currently at a machine I typically work from, so I can't provide working code nor play around to find a better option, but will edit this answer when I can to show how you might be able to do this.

Solution 5

[me@localhost ~]$ echo $$
30399
[me@localhost ~]$ cat iostat.py 
#!/usr/bin/env python3.4 

import multiprocessing
import os
d = multiprocessing.Process(target=os.system,args=('iostat 2 > a.txt',))
d.start()

[me@localhost ~]$ ./iostat.py &
[1] 31068
[me@localhost ~]$ watch -n 3 'pstree -p 30399'
[me@localhost ~]$ 

This gave me the PID of iostat See image. process tree

Share:
38,289
tazim
Author by

tazim

Updated on July 09, 2022

Comments

  • tazim
    tazim over 1 year

    I am using python's multiprocessing module to spawn new process

    as follows :

    import multiprocessing
    import os
    d = multiprocessing.Process(target=os.system,args=('iostat 2 > a.txt',))
    d.start()
    

    I want to obtain pid of iostat command or the command executed using multiprocessing module

    When I execute :

     d.pid 
    

    it gives me pid of subshell in which this command is running .

    Any help will be valuable .

    Thanks in advance

  • rakslice
    rakslice almost 13 years
    If you want to use subprocess.Popen without the shell option, you can't give it a shell command (like the single string with multiple parameters and a redirection shown here).
  • Amit
    Amit over 12 years
    On a Mac: ps -o pid,ppid -ax | grep <PPID> | cut -f 1 -d " " | tail -1
  • rakslice
    rakslice over 12 years
    Gah, yeah, my answer's probably Linux-specific.
  • koniiiik
    koniiiik over 10 years
    Why do os.kill(pid.pid, sig) instead of pid.send_signal(sig)? As in, why not use the API psutil gives you already? Also, pid.send_signal is supposedly safer as it should avoid race conditions such as when the original process with the given PID finishes and another one uses the same PID.
  • zhanxw
    zhanxw over 10 years
    Agree. pid.send_signal(sig) seems safer. Thank you.
  • Treviño
    Treviño almost 10 years
    To get all children recursively, you can instead use: subprocess.Popen('pstree -p %d | perl -ne \'print "$1 " while /\((\d+)\)/g\'' % parent_pid, shell=True, stdout=subprocess.PIPE)
  • Wyrmwood
    Wyrmwood almost 5 years
    This is incorrect. The process pid is bash. The child process will be something else, usually pid+1, but can be found with something like pgrep -P parent_pid. Nevermind your example would get stuck :-)