2010-09-09 18 views
6

En mi clase, ejecuto 4 procesos.¿Cómo puedo saber cuándo murió un proceso hijo?

from multiprocessing import Process 

    procs = (
      Process(target=ClassOne, name='ClassOne'), 
      Process(target=ClassTwo, name='ClassTwo'), 
      Process(target=ClassThree, name='ClassThree'), 
      Process(target=ClassFour, name='ClassFour'), 
      ) 

    for p in procs: 
     p.daemon = False 
     p.start() 

Me gustaría recibir una notificación cuando uno de mis hijos haya fallecido, así puedo matar al otro y a mí mismo.

Respuesta

3

apenas define un manejador de señales para SIGCHLD, inspeccionar el marco devuelto por el niño acaba de muertos para recuperar la información que necesita de ella ... y si es necesario la salida() el padre también :)

+0

@Spi, si buscaba una solución específica para Unix, debería haber indicado esto en la pregunta. – Constantin

+0

@Constantin, Win no tiene señales? Tengo mucha curiosidad, no tengo polémica :) – drAlberT

+1

Windows tiene una API de señal C, pero no las usa de forma nativa. En Windows, puede esperar trivialmente en los identificadores de procesos secundarios. Simplemente esperará a que se marque la primera señal, luego terminará a los demás y luego se irá. – MSalters

-2

Aquí hay una solución de Windows. Utiliza la llamada a la API WaitForMultipleObjects. Para Unix os.waitpid puede hacer el trabajo.

import multiprocessing as mp 
import ctypes 


SYNCHRONIZE = 0x00100000 
INFINITE = -1 


def mbox(msg): 
    ctypes.windll.user32.MessageBoxW(0, msg, u'spam', 0) 


if __name__ == '__main__': 

    # start 2 processes 
    procs = [mp.Process(target=mbox, args=(msg,)) for msg in u'ab'] 
    for p in procs: 
    p.start() 

    # wait for at least one process to terminate 
    handles = [ 
    ctypes.windll.kernel32.OpenProcess(SYNCHRONIZE, False, p.pid) 
    for p in procs] 
    array_type = ctypes.c_long * len(handles) 
    handle_array = array_type(*handles) 
    ctypes.windll.kernel32.WaitForMultipleObjects(
    len(handles), handle_array, False, INFINITE) 

    # terminate the rest 
    for p in procs: 
    p.terminate() 

    # exit 
    print 'done' 
+1

El problema es que waitpid() toma solo ** un ** pid y está bloqueando hasta el tiempo de espera ... WaitForMultipleObjects() hace el trabajo ya que puede manejar muchos objetos al mismo tiempo ... ¿Puede proporcionar un POC? usando waitpid()? –

+0

@Spi, como aparentemente descubrió usted mismo, 'waitpid' se puede usar para esperar la muerte del hijo" i-dont-care-which-one ". El problema es que puede tener otros hijos generados y 'waitpid' indicará su terminación también ... – Constantin

1

La manera más simple sería esperar explícitamente hasta que todos los procesos se hayan realizado.

while multiprocessing.active_children(): 
    pass 

Esto no es un evento impulsado como podría querer, pero hará el trabajo en su ejemplo. También asegúrese de que import multiprocessing.

+2

OP quiere terminar cuando * al menos un niño muere, no cuando todos mueren. – Constantin

+2

Esta solución usará una CPU para espera ocupada y no es la solución a la pregunta señalada por @Constantin. –

3

Se es posible usar os.waitpid() pasando -1 como el primer argumento y como el segundo.

  • El primer argumento significa que la solicitud pertenece a cualquier elemento secundario del proceso actual.
  • El segundo argumento significa que se comporta como wait().

La función devuelve una tupla con el pid del niño muerto y su código de salida.

0

Quizás desee consultar la clase AutoJoiningProcess en la respuesta al this similar question.

Si está preparado para agregar a su código una dependencia de gobject (parte de PyGTK), entonces AutoJoiningProcess le permitirá escuchar una señal que se emite cuando termina un proceso. En esa señal, podrías responder como quieras.

Cuestiones relacionadas