139

Is there a way to check to see if a pid corresponds to a valid process? I'm getting a pid from a different source other than from os.getpid() and I need to check to see if a process with that pid doesn't exist on the machine.

I need it to be available in Unix and Windows. I'm also checking to see if the PID is NOT in use.

Omer Dagan
  • 14,868
  • 16
  • 44
  • 60
Evan Fosmark
  • 98,895
  • 36
  • 105
  • 117
  • 5
    Windows is a non-standard OS. These kinds of things are NOT portable. Knowing you cannot have both, which is your priority? Pick one as a priority and edit the question. – S.Lott Feb 20 '09 at 11:01
  • 38
    @S.Lott *Windows is a non-standard OS* This is one of the most silly remark I've seen on SO... – Piotr Dobrogost Jul 12 '13 at 21:08
  • 3
    @Piotr Dobrogost: Can you provide code that handles POSIX standard unix and non-POSIX standard Windows? If so, please provide an answer that (a) solves the problem and (b) makes it clear that Windows is somehow compliant with the POSIX standard. – S.Lott Jul 15 '13 at 17:49
  • 6
    @PiotrDobrogost I think S.Lott's remark was more about implementation details and API support than market share. – Roy Tinker Apr 08 '14 at 18:46
  • 6
    Windows certainly has less in common with other popular OSes than the rest do with each other. (Anybody who does web development may liken it to a similarly infamous Microsoft product.) But in response to @S.Lott: I rarely write Python code for Windows that's not supposed to also work on Linux, OSX, BSD, etc, so I honestly don't think 'pick on as a priority' is helpful advice, especially since Python abstracts platform differences away as much as practicable. – Michael Scheper Dec 21 '15 at 00:34
  • linux only: `import subprocess; subprocess.check_call('ps -p 12345', shell=True);` and for cross-platform use `psutil` – Trevor Boyd Smith Dec 06 '18 at 16:13

15 Answers15

190

Sending signal 0 to a pid will raise an OSError exception if the pid is not running, and do nothing otherwise.

import os

def check_pid(pid):        
    """ Check For the existence of a unix pid. """
    try:
        os.kill(pid, 0)
    except OSError:
        return False
    else:
        return True
Brandon Rhodes
  • 83,755
  • 16
  • 106
  • 147
mluebke
  • 8,588
  • 7
  • 35
  • 31
  • Also, doesn't this kill the process? – Evan Fosmark Feb 20 '09 at 04:35
  • 3
    Works for sure in linux and OSX, I can't speak for Windows. It does not kill the process in the sense that you are asking, it sends signal 0, which is basically "Are you running?". – mluebke Feb 20 '09 at 04:40
  • Ah, I see. Thanks for the code, but what I really need is something that runs in Windows as well. – Evan Fosmark Feb 20 '09 at 05:02
  • Why SIG_DFL? Signal 0 has no name, and should (to my knowledge) be written as 0, not as SIG_DFL (which does not have a mandated value, and can stand for some other value on other systems). – C. K. Young Feb 20 '09 at 05:35
  • 1
    In the python signal module, signal 0 is defined as SIG_DFL. Unless I am misinterpreting the module. – mluebke Feb 20 '09 at 06:06
  • 11
    This definitely doesn't work on Windows, as there's no such thing as UNIX-like signals. – Alexander Lebedev Feb 20 '09 at 06:14
  • 14
    To be complete, you should also check for the error number to make sure it is 3 (catch the exception and check for first arg). This is important if the target process exists but you don't have permission to send signal (for whatever reason). – haridsv Apr 06 '10 at 22:21
  • 8
    Supported by windows now. http://docs.python.org/library/os.html?highlight=os.kill#os.kill – michael Jun 08 '11 at 17:24
  • 19
    os.kill is supported on Windows, but `os.kill(pid, 0)` is the same as `os.kill(pid, signal.CTRL_C_EVENT)` which may terminate the process (or fail). I get an `OSError` where `errno==EINVAL` when I try this on a subprocess. – Jason R. Coombs Feb 22 '12 at 12:40
  • 3
    This code is incorrect 'cause it doesn't take EPERM error into account, returning False for a PID which actually exists. This is the right answer: http://stackoverflow.com/a/6940314/376587 – Giampaolo Rodolà May 18 '15 at 14:15
  • 2
    Important note- This works only if the process in question is owned by the user running check_pid() – Omer Dagan Jan 25 '17 at 12:21
  • in python3 os.kill() throws ProcessLookupError – martinkunev May 26 '17 at 15:15
  • @Jason R. Coombs This is the issue about why not "os.kill on Windows should accept zero as signal" : https://bugs.python.org/issue14480 – selfboot Jun 21 '17 at 02:23
106

Have a look at the psutil module:

psutil (python system and process utilities) is a cross-platform library for retrieving information on running processes and system utilization (CPU, memory, disks, network) in Python. [...] It currently supports Linux, Windows, OSX, FreeBSD and Sun Solaris, both 32-bit and 64-bit architectures, with Python versions from 2.6 to 3.4 (users of Python 2.4 and 2.5 may use 2.1.3 version). PyPy is also known to work.

It has a function called pid_exists() that you can use to check whether a process with the given pid exists.

Here's an example:

import psutil
pid = 12345
if psutil.pid_exists(pid):
    print("a process with pid %d exists" % pid)
else:
    print("a process with pid %d does not exist" % pid)

For reference:

Community
  • 1
  • 1
moooeeeep
  • 31,622
  • 22
  • 98
  • 187
  • 7
    Here's [how `psutil` implements `pid_exists()` on POSIX](https://github.com/giampaolo/psutil/blob/5ba055a8e514698058589d3b615d408767a6e330/psutil/_psposix.py#L28-L53). Compare with [@Giampaolo Rodolà's answer (author of `psutil`)](https://stackoverflow.com/a/6940314/4279) – jfs Aug 10 '17 at 06:02
  • I had an instance where pid_exists stopped being reliable on Windows. It was mis-reporting dead pids as being in use. This is a reminder to keep your psutil module updated from time to time - especially when doing OS upgrades. – Damon Brodie Sep 27 '18 at 15:07
70

mluebke code is not 100% correct; kill() can also raise EPERM (access denied) in which case that obviously means a process exists. This is supposed to work:

(edited as per Jason R. Coombs comments)

import errno
import os

def pid_exists(pid):
    """Check whether pid exists in the current process table.
    UNIX only.
    """
    if pid < 0:
        return False
    if pid == 0:
        # According to "man 2 kill" PID 0 refers to every process
        # in the process group of the calling process.
        # On certain systems 0 is a valid PID but we have no way
        # to know that in a portable fashion.
        raise ValueError('invalid PID 0')
    try:
        os.kill(pid, 0)
    except OSError as err:
        if err.errno == errno.ESRCH:
            # ESRCH == No such process
            return False
        elif err.errno == errno.EPERM:
            # EPERM clearly means there's a process to deny access to
            return True
        else:
            # According to "man 2 kill" possible error values are
            # (EINVAL, EPERM, ESRCH)
            raise
    else:
        return True

You can't do this on Windows unless you use pywin32, ctypes or a C extension module. If you're OK with depending from an external lib you can use psutil:

>>> import psutil
>>> psutil.pid_exists(2353)
True
user3758232
  • 758
  • 5
  • 19
Giampaolo Rodolà
  • 12,488
  • 6
  • 68
  • 60
24

The answers involving sending 'signal 0' to the process will work only if the process in question is owned by the user running the test. Otherwise you will get an OSError due to permissions, even if the pid exists in the system.

In order to bypass this limitation you can check if /proc/<pid> exists:

import os

def is_running(pid):
    if os.path.isdir('/proc/{}'.format(pid)):
        return True
    return False

This applies to linux based systems only, obviously.

Omer Dagan
  • 14,868
  • 16
  • 44
  • 60
  • wrong. [`PermissionError` means pid exists](https://stackoverflow.com/a/20186516/4279), you get `ProcessLookupError` if pid doesn't exist. – jfs Jan 26 '18 at 14:48
  • The `OSError` due to denied permission can be differentiated from other ones - either via looking at errno or via catching the more specialized `PermissionError`/`ProcessLookupError` exceptions which derive from `OSError`. Futhermore, you only get the permission error if the process exists. Thus, your example is just an alternative method that works on Linux and some other Unices but it isn't more complete than properly calling `os.kill(pid, 0)`. – maxschlepzig Feb 06 '18 at 20:14
  • This solution is not corss-platform. The OP want it be available on Unix and Windows. The `/proc` procfs only exits on Linux, not even on BSD or OSX. – C.W. Sep 26 '18 at 13:14
  • This method fails if /proc is mounted hidepid=2, the process won't show in the list if it's owned by another user. – Perkins Jan 26 '19 at 03:18
11

In Python 3.3+, you could use exception names instead of errno constants. Posix version:

import os

def pid_exists(pid): 
    if pid < 0: return False #NOTE: pid == 0 returns True
    try:
        os.kill(pid, 0) 
    except ProcessLookupError: # errno.ESRCH
        return False # No such process
    except PermissionError: # errno.EPERM
        return True # Operation not permitted (i.e., process exists)
    else:
        return True # no error, we can send a signal to the process
jfs
  • 399,953
  • 195
  • 994
  • 1,670
8

Look here for windows-specific way of getting full list of running processes with their IDs. It would be something like

from win32com.client import GetObject
def get_proclist():
    WMI = GetObject('winmgmts:')
    processes = WMI.InstancesOf('Win32_Process')
    return [process.Properties_('ProcessID').Value for process in processes]

You can then verify pid you get against this list. I have no idea about performance cost, so you'd better check this if you're going to do pid verification often.

For *NIx, just use mluebke's solution.

Alexander Lebedev
  • 5,968
  • 1
  • 20
  • 30
  • This worked well for me. I wanted to check for a process name so swapped out "ProcessID" for "Name" and also converted it into a check for in list to return True or False. – JamesR Apr 24 '20 at 12:17
7

Building upon ntrrgc's I've beefed up the windows version so it checks the process exit code and checks for permissions:

def pid_exists(pid):
    """Check whether pid exists in the current process table."""
    if os.name == 'posix':
        import errno
        if pid < 0:
            return False
        try:
            os.kill(pid, 0)
        except OSError as e:
            return e.errno == errno.EPERM
        else:
            return True
    else:
        import ctypes
        kernel32 = ctypes.windll.kernel32
        HANDLE = ctypes.c_void_p
        DWORD = ctypes.c_ulong
        LPDWORD = ctypes.POINTER(DWORD)
        class ExitCodeProcess(ctypes.Structure):
            _fields_ = [ ('hProcess', HANDLE),
                ('lpExitCode', LPDWORD)]

        SYNCHRONIZE = 0x100000
        process = kernel32.OpenProcess(SYNCHRONIZE, 0, pid)
        if not process:
            return False

        ec = ExitCodeProcess()
        out = kernel32.GetExitCodeProcess(process, ctypes.byref(ec))
        if not out:
            err = kernel32.GetLastError()
            if kernel32.GetLastError() == 5:
                # Access is denied.
                logging.warning("Access is denied to get pid info.")
            kernel32.CloseHandle(process)
            return False
        elif bool(ec.lpExitCode):
            # print ec.lpExitCode.contents
            # There is an exist code, it quit
            kernel32.CloseHandle(process)
            return False
        # No exit code, it's running.
        kernel32.CloseHandle(process)
        return True
speedplane
  • 15,673
  • 16
  • 86
  • 138
  • Actually, according to http://msdn.microsoft.com/en-us/library/windows/desktop/ms683189%28v=vs.85%29.aspx, `GetExistCodeProcess` requires the `PROCESS_QUERY_INFORMATION` and `PROCESS_QUERY_LIMITED_INFORMATION` access rights. – augustomen Oct 17 '14 at 15:29
  • Note that the code is wrong. `GetExitCodeProcess` receives a handle and a pointer and in this sample it's receiving an `ExitCodeProcess` structure as the second parameter when it should be only a pointer. – Fabio Zadrozny Apr 10 '18 at 18:55
  • After OpenProcess, it's a good idea to check GetLastError. An ERROR_ACCESS_DENIED there means the process exists! Here's a complete example using this: https://gist.github.com/ociule/8a48d2a6b15f49258a87b5f55be29250 – ociule Jan 20 '20 at 09:50
4

Combining Giampaolo Rodolà's answer for POSIX and mine for Windows I got this:

import os
if os.name == 'posix':
    def pid_exists(pid):
        """Check whether pid exists in the current process table."""
        import errno
        if pid < 0:
            return False
        try:
            os.kill(pid, 0)
        except OSError as e:
            return e.errno == errno.EPERM
        else:
            return True
else:
    def pid_exists(pid):
        import ctypes
        kernel32 = ctypes.windll.kernel32
        SYNCHRONIZE = 0x100000

        process = kernel32.OpenProcess(SYNCHRONIZE, 0, pid)
        if process != 0:
            kernel32.CloseHandle(process)
            return True
        else:
            return False
Community
  • 1
  • 1
Alicia
  • 1,132
  • 1
  • 14
  • 28
  • The windows version does not work for me on windows 8.1. You have to check `GetExitCodeProcess` and make sure you even have access. – speedplane May 01 '14 at 14:04
  • Using `kernel32.OpenProcess` solely is not enough. As [here](http://www.madebuild.org/blog/?p=30) pointed out **"if the process exited recently, a pid may still exist for the handle."** If `kernel32.OpenProcess` returns non zero value, we still need `kernel32.GetExitCodeProcess` further to check the exit code. – Meow Jun 17 '16 at 05:32
2

This will work for Linux, for example if you want to check if banshee is running... (banshee is a music player)

import subprocess

def running_process(process):
    "check if process is running. < process > is the name of the process."

    proc = subprocess.Popen(["if pgrep " + process + " >/dev/null 2>&1; then echo 'True'; else echo 'False'; fi"], stdout=subprocess.PIPE, shell=True)

    (Process_Existance, err) = proc.communicate()
    return Process_Existance

# use the function
print running_process("banshee")
L3viathan
  • 26,748
  • 2
  • 58
  • 81
BARSPIN
  • 21
  • 1
  • This method clearly is inferior in comparison to either using `os.kill(pid, 0)` or looking at `/proc/{pid}`. Instead of executing one syscall your code forks a child, execs a shell in that child, the shell interprets your superfluous mini shell-script, the shell forks another child that execs pgrep and finally pgrep iterates over `/proc`. Your answer doesn't answer the posted question. The OP asked for a method given a PID. Your method requires a process name. – maxschlepzig Feb 06 '18 at 20:21
2

In Windows, you can do it in this way:

import ctypes
PROCESS_QUERY_INFROMATION = 0x1000
def checkPid(pid):
    processHandle = ctypes.windll.kernel32.OpenProcess(PROCESS_QUERY_INFROMATION, 0,pid)
    if processHandle == 0:
        return False
    else:
        ctypes.windll.kernel32.CloseHandle(processHandle)
    return True

First of all, in this code you try to get a handle for process with pid given. If the handle is valid, then close the handle for process and return True; otherwise, you return False. Documentation for OpenProcess: https://msdn.microsoft.com/en-us/library/windows/desktop/ms684320%28v=vs.85%29.aspx

Andrei
  • 21
  • 3
0

The following code works on both Linux and Windows, and not depending on external modules

import os
import subprocess
import platform
import re

def pid_alive(pid:int):
    """ Check For whether a pid is alive """


    system = platform.uname().system
    if re.search('Linux', system, re.IGNORECASE):
        try:
            os.kill(pid, 0)
        except OSError:
            return False
        else:
            return True
    elif re.search('Windows', system, re.IGNORECASE):
        out = subprocess.check_output(["tasklist","/fi",f"PID eq {pid}"]).strip()
        # b'INFO: No tasks are running which match the specified criteria.'

        if re.search(b'No tasks', out, re.IGNORECASE):
            return False
        else:
            return True
    else:
        raise RuntimeError(f"unsupported system={system}")

It can be easily enhanced in case you need

  1. other platforms
  2. other language
oldpride
  • 761
  • 7
  • 15
0

I found that this solution seems to work well in both windows and linux. I used psutil to check.

import psutil
import subprocess
import os
p = subprocess.Popen(['python', self.evaluation_script],stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 

pid = p.pid

def __check_process_running__(self,p):
    if p is not None:
        poll = p.poll()
        if poll == None:
            return True
    return False
    
def __check_PID_running__(self,pid):
    """
        Checks if a pid is still running (UNIX works, windows we'll see)
        Inputs:
            pid - process id
        returns:
            True if running, False if not
    """
    if (platform.system() == 'Linux'):
        try:
            os.kill(pid, 0)
            if pid<0:               # In case code terminates
                return False
        except OSError:
            return False 
        else:
            return True
    elif (platform.system() == 'Windows'):
        return pid in (p.pid for p in psutil.process_iter())
Pat
  • 627
  • 1
  • 9
  • 24
0

Another option for Windows is through the pywin32 package:

pid in win32process.EnumProcesses()

The win32process.EnumProcesses() returns PIDs for currently running processes.

ROJI
  • 131
  • 1
  • 5
0

After trying different solutions, relying on psutil was the best OS agnostic way to accurately say if a PID exists. As suggested above, psutil.pid_exists(pid) works as intended but the downside is, it includes stale process IDs and processes that were terminated recently.

Solution: Check if process ID exists and if it is actively running.

import psutil

def process_active(pid: int or str) -> bool:
    try:
        process = psutil.Process(pid)
    except psutil.Error as error:  # includes NoSuchProcess error
        return False
    if psutil.pid_exists(pid) and process.status() == psutil.STATUS_RUNNING:
        return True
Vignesh Rao
  • 136
  • 3
-2

I'd say use the PID for whatever purpose you're obtaining it and handle the errors gracefully. Otherwise, it's a classic race (the PID may be valid when you check it's valid, but go away an instant later)

Damien_The_Unbeliever
  • 234,701
  • 27
  • 340
  • 448
  • I should have been more specific - I'm checking for the INVALIDITY. So, I basically want to be able to see if a pid is NOT in use. – Evan Fosmark Feb 20 '09 at 08:29
  • 1
    But what will you do with that answer? The instant after you've gained that knowledge, something might use that pid. – Damien_The_Unbeliever Feb 20 '09 at 09:40
  • @Damien_The_Unbeliever - that's alright if something is using it after I gain that knowledge, and I understand what you're saying about the race condition, but I can assure you that it doesn't apply for my situation. – Evan Fosmark Feb 20 '09 at 17:32