2009-02-20 18 views
69

¿Hay alguna manera de verificar si un pid corresponde a un proceso válido? Obtengo un pid de una fuente diferente que no sea os.getpid() y necesito verificar si un proceso con ese pid no existe en la máquina.¿Cómo comprobar si existe un proceso con un pid dado en Python?

Necesito que esté disponible en Unix y Windows. También estoy verificando si el PID NO está en uso.

+1

Windows es un sistema operativo no estándar. Este tipo de cosas NO son portátiles. Sabiendo que no puedes tener ambas cosas, ¿cuál es tu prioridad? Elija uno como prioridad y edite la pregunta. –

+20

@ S.Lott * Windows es un sistema operativo no estándar * Este es uno de los comentarios más tontos que he visto en SO ... –

+1

@Piotr Dobrogost: ¿Puede proporcionar un código que maneje el estándar POSIX estándar UNIX y no POSIX? Windows? De ser así, proporcione una respuesta que (a) resuelva el problema y (b) aclare que Windows cumple de alguna manera con el estándar POSIX. –

Respuesta

115

La señal de envío 0 a un pid generará una excepción OSError si el pid no se está ejecutando, y no hará nada de lo contrario.

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 
+0

¿Esto solo funciona en máquinas basadas en Unix? –

+0

Además, ¿esto no acaba con el proceso? –

+3

Funciona en Linux y OSX, no puedo hablar por Windows. No mata el proceso en el sentido en que lo pides, envía la señal 0, que es básicamente "¿Estás corriendo?". – mluebke

6

Look here de manera de obtener la lista completa de los procesos en ejecución con sus identificaciones específicas de Windows. Sería algo así como

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] 

A continuación, puede verificar pid que obtiene en contra de esta lista. No tengo idea del costo de rendimiento, así que será mejor que lo compruebes si vas a hacer la verificación de pid a menudo.

Para * NIx, solo use la solución de mluebke.

-1

Yo diría que use el PID para cualquier propósito que lo esté obteniendo y maneje los errores con gracia. De lo contrario, es una carrera clásica (el PID puede ser válido cuando se comprueba que es válido, pero se va un instante después)

+0

Debería haber sido más específico, estoy buscando la INVALIDEZ. Entonces, básicamente quiero poder ver si un pid NO está en uso. –

+0

¿Pero qué vas a hacer con esa respuesta? El instante después de que hayas adquirido ese conocimiento, algo podría usar ese pid. –

+0

@Damien_The_Unbeliever - está bien si algo lo está usando después de obtener ese conocimiento, y entiendo lo que dices sobre la condición de carrera, pero puedo asegurarte que no se aplica a mi situación. –

47

mluebke código no es 100% correcto; kill() también puede generar EPERM (acceso denegado), en cuyo caso eso obviamente significa que existe un proceso. Esto se supone que funciona:

(editado de acuerdo con los comentarios de Jason R. Coombs)

import errno 
import os 
import sys 

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 

No se puede hacer esto en Windows a menos que utilice pywin32, ctypes o un módulo de extensión C. Si estás bien con función de un lib externa puede utilizar psutil:

>>> import psutil 
>>> psutil.pid_exists(2353) 
True 
+0

haridsv sugiere que la prueba debe ser e.errno! = 3; quizás e.errno! = errno.ESRCH –

+0

¿Por qué? ESRCH significa "no hay tal proceso". –

+2

Derecha. Como ESRCH significa "no hay tal proceso", errno! = ESRCH significa "no existe tal proceso" o "existe proceso", que es muy similar al nombre de la función. Usted mencionó específicamente EPERM, pero ¿qué implican los otros posibles códigos de error? Parece incorrecto señalar un código de error que está vagamente relacionado con la intención del control, mientras que ESRCH parece estar estrechamente relacionado. –

40

Tenga una mirada en el módulo psutil:

psutil (sistema de pitón y servicios de proceso) es una biblioteca multiplataforma para recuperar información en procesos en ejecución y utilización del sistema (CPU, memoria, discos, red) en Python. [...] En la actualidad apoya Linux, de Windows, OSX, FreeBSD y Sun Solaris, dos de 32 bits y64 bits arquitecturas, con versiones de Python desde 2,6 a 3.4 (los usuarios de Python 2.4 y 2.5 pueden usar la versión 2.1.3). PyPy también se sabe que funciona.

Tiene una función llamada pid_exists() que puede usar para verificar si existe un proceso con el pid dado.

Aquí está un ejemplo:

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 

para la referencia:

+2

Aquí está [cómo 'psutil' implementa' pid_exists() 'en POSIX] (https://github.com/giampaolo/psutil/blob/5ba055a8e514698058589d3b615d408767a6e330/psutil/_psposix.py # L28-L53). Compare con la respuesta de [@Giampaolo Rodolà (autor de 'psutil')] (https://stackoverflow.com/a/6940314/4279) – jfs

4

Combinando Giampaolo Rodolà's answer for POSIX y mine for Windows Tengo esto:

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 
+0

La versión de Windows no funciona para mí en Windows 8.1. Debes verificar 'GetExitCodeProcess' y asegurarte de que incluso tienes acceso. – speedplane

+0

El uso de 'kernel32.OpenProcess' no es suficiente. Como [aquí] (http://www.madebuild.org/blog/?p=30) señaló ** "si el proceso salió recientemente, aún puede existir un pid para el manejador". ** Si 'kernel32.OpenProcess 'devuelve un valor distinto de cero, aún necesitamos' kernel32.GetExitCodeProcess' para verificar el código de salida. – Meow

6

En Python 3.3+, se puede usar nombres de excepción en lugar de constantes errno. 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 
6

Sobre la base de ntrrgc He reforzado la versión ventanas, así que comprueba el código de salida del proceso y los controles de permisos:

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 
+0

En realidad, según http://msdn.microsoft.com/en-us/library/windows/desktop/ms683189%28v=vs.85%29.aspx, 'GetExistCodeProcess' requiere el acceso' PROCESS_QUERY_INFORMATION' y 'PROCESS_QUERY_LIMITED_INFORMATION' derechos. –

2

Esto funciona para Linux, por ejemplo, si desea para comprobar si se está ejecutando alma en pena ... (Banshee es un reproductor de música)

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") 
+0

Este método es claramente inferior en comparación con usar 'os.kill (pid, 0)' o mirar '/ proc/{pid}'. En lugar de ejecutar un syscall, su código bifurca a un niño, ejecuta un shell en ese niño, el intérprete interpreta su superfluo mini guión de shell, el intérprete de comandos crea otro hijo que ejecuta pgrep y finalmente pgrep itera sobre '/ proc'.Su respuesta no responde a la pregunta publicada. El OP pidió un método dado un PID. Su método requiere un nombre de proceso. – maxschlepzig

2

en Windows, puede hacerlo de esta manera:

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 

En primer lugar, en este código intenta obtener un control para el proceso con pid dado. Si el identificador es válido, cierre el identificador del proceso y devuelva True; de lo contrario, devuelve False. Documentación para OpenProcess: https://msdn.microsoft.com/en-us/library/windows/desktop/ms684320%28v=vs.85%29.aspx

+0

Por favor, agregue alguna explicación a su código. –

5

Las respuestas que envían el envío de la 'señal 0' al proceso funcionarán en solo si el proceso en cuestión es propiedad del usuario que ejecuta la prueba. De lo contrario, obtendrá un OSError debido a permisos, incluso si el pid existe en el sistema.

Con el fin de evitar esta limitación se puede comprobar si existe /proc/<pid>:

import os 

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

¡Esta es una buena respuesta, gente! +1 – Havok

+0

mal. ['PermissionError' significa que existe el pid] (https://stackoverflow.com/a/20186516/4279), obtienes' ProcessLookupError' si pid no existe. – jfs

+0

El 'OSError' debido a un permiso denegado se puede diferenciar de otros, ya sea mirando a errno o atrapando las excepciones más especializadas' PermissionError'/'ProcessLookupError' que se derivan de' OSError'. Además, solo obtiene el error de permiso si el proceso existe. Por lo tanto, su ejemplo es simplemente un método alternativo que funciona en Linux y algunos otros Unices pero no es más completo que llamar apropiadamente 'os.kill (pid, 0)'. – maxschlepzig

Cuestiones relacionadas