18

I have this:

def get_process():
    pids = []
    process = None
    for i in os.listdir('/proc'):
        if i.isdigit():
            pids.append(i)

    for pid in pids:
        proc = open(os.path.join('/proc', pid, 'cmdline'), 'r').readline()
        if proc == "Something":
            process = pid

    return process          

def is_running(pid):
    return os.path.exists("/proc/%s" % str(pid))

Then i do this:

process = get_process()
if process == None:
    #do something
else:
    #Wait until the process end
    while is_running(process):
        pass

I think this is not the best way to wait for the process to terminate, there must be some function wait or something, but i can't find it.

Disclaimer: The process is not a child process

Niko
  • 313
  • 1
  • 2
  • 7

4 Answers4

19

I'm not really a Python programmer, but apparently Python does have os.waitpid(). That should consume less CPU time and provide a much faster response than, say, trying to kill the process at quarter-second intervals.


Addendum: As Niko points out, os.waitpid() may not work if the process is not a child of the current process. In that case, using os.kill(pid, 0) may indeed be the best solution. Note that, in general, there are three likely outcomes of calling os.kill() on a process:

  1. If the process exists and belongs to you, the call succeeds.
  2. If the process exists but belong to another user, it throws an OSError with the errno attribute set to errno.EPERM.
  3. If the process does not exist, it throws an OSError with the errno attribute set to errno.ESRCH.

Thus, to reliably check whether a process exists, you should do something like

def is_running(pid):        
    try:
        os.kill(pid, 0)
    except OSError as err:
        if err.errno == errno.ESRCH:
            return False
    return True
Ilmari Karonen
  • 49,047
  • 9
  • 93
  • 153
  • 1
    That only works for a child process. It would be great if this works for any process. – Niko Oct 04 '11 at 21:27
  • 1
    This won't work on Windows - the kill signal unconditionally kills the process sent the signal ([docs](https://docs.python.org/2/library/os.html#os.kill)). – dbn Jul 15 '14 at 18:32
2

Since that method would only work on linux, for linux/osx support, you could do:

import time
import os

def is_running(pid):
    stat = os.system("ps -p %s &> /dev/null" % pid)
    return stat == 0

pid = 64463

while is_running(pid):
    time.sleep(.25)

Edit - Per tMc's comment about excessive processes

Referencing: How to check if there exists a process with a given pid in Python?

Wouldn't this use less resources (I havent tested), than listing on the filesystem and opening FDs to all the results?

import time
import os

def is_running(pid):        
    try:
        os.kill(pid, 0)
    except OSError:
        return False

    return True

pid = 64463

while is_running(pid):
    time.sleep(.25)
Community
  • 1
  • 1
jdi
  • 90,542
  • 19
  • 167
  • 203
  • 1
    this will spawn a subshell, which will spawn a process for the ps command, creating 8 processes a second. – tMC Oct 04 '11 at 20:36
  • What if the call to os.system were replaced with the method he uses [here](http://stackoverflow.com/questions/568271/check-if-pid-is-not-in-use-in-python/568285#568285) ? – jdi Oct 04 '11 at 20:46
  • Thats better than stating /proc/ IMHO. – tMC Oct 04 '11 at 20:49
  • It seems a better idea, i'll use it – Niko Oct 04 '11 at 21:32
  • Should I also write `is_running()` inside a `try/except`? – alper Jul 25 '20 at 20:28
  • 1
    @alper no that isn't necessary. The kill is the one to likely raise if the pid is gone. The running check should not be exceptional. – jdi Jul 26 '20 at 21:10
1

import time, then use time.sleep(#):

import time
process = get_process()
if process == None:
    #do something
else:
    #Wait until the process end
    while is_running(process):
        time.sleep(0.25)

I also have that exact same function in several of my scrips to read through /proc/#/cmdline to check for a PID.

chown
  • 51,908
  • 16
  • 134
  • 170
  • This prevents the program uses 100% of one of the cores of my cpu, i hadnt really noticed that :P but anyway there should be some function, however I think this solution isn't so bad. – Niko Oct 04 '11 at 20:04
  • With threading you could do somewhat better, but it gets really overcomplicated for this simple of a task and threads have expensive overhead. – chown Oct 04 '11 at 20:26
0

A simple and reliable way of doing this with Python is by getting a list of PIDs with psutil, and then checking if your PID is in that list of running PIDs:

import psutil

def check_pid(pid):

    if int(pid) in psutil.pids(): ## Check list of PIDs
        return True ## Running
    else:
        return False ## Not Running

To use it, just run it in a simple while loop.

pid = 1000
running = True

while running == True:
    running = check_pid(int(pid))
    (Do stuff *until* PID ends)

(Do stuff *after* PID ends)

Or you could just put all that into one function...

def pause_while_running(pid):

    running = True

    while running:
        if int(pid) not in psutil.pids():
            running = False
        time.sleep(5)

and use like

pause_while_running(pid)
(do stuff after PID ended)
FallenSpaces
  • 312
  • 1
  • 4
  • 17