2011-12-30 7 views
9

Estoy trabajando en un código de servidor que usa fork() y exec para crear procesos secundarios. El PID del niño se registra cuando fork() tiene éxito y se limpia cuando se ha detectado la señal CHILD.¿La señal KILL sale de un proceso de inmediato?

Si el servidor necesita detenerse, todos los programas se eliminan, eventualmente con una señal KILL. Ahora, esto funciona mediante iteración a través de todos los PID registrados y esperando que el manejador de señal CHILD elimine los PID. Esto fallará si el programa hijo no salió correctamente. Por lo tanto, quiero usar kill en combinación con waitpid para asegurarme de que la lista PID esté limpia y registrar y hacer otras cosas de lo contrario.

Considérese el siguiente ejemplo de código:

kill(pid, SIGKILL); 
waitpid(pid, NULL, WNOHANG); 

Extracto de waitpid(2):

waitpid(): en caso de éxito, devuelve el identificador de proceso del niño cuyo estado ha cambiado; si se especificó WNOHANG y existen uno o más hijos (s) especificados por pid, pero aún no han cambiado el estado, se devuelve 0. En caso de error, se devuelve -1.

¿El proceso dado por pid siempre se ha ido antes de que la próxima función entre? ¿waitpid siempre devolverá -1 en el caso anterior?

+2

Una señal KILL es bastante brutal, ¿por qué no INT o HUP? Y también, ¿cuál es el código de retorno de 'kill' syscall? – fge

+0

"esperando que el manejador de señal CHILD ..." - No hay ningún manejador de señal para SIGKILL, ¿sabes? Todas las señales, excepto SIGSTOP y SIGKILL, harán lo establecido por 'sigaction' (por ejemplo, invocar un controlador), o por defecto. SIGSTOP simplemente se detiene, y SIGKILL simplemente mata el proceso. Siempre. No hay manejo o condicional. (La excepción es que el comando 'kill' falla porque no tiene suficientes derechos.) – Damon

+0

@Damon:' SIGKILL' no puede ser ignorado por el proceso de destino, eso es correcto. Pero esa no es la pregunta/problema.La llamada al sistema 'kill (2)' en el proceso fuente puede regresar antes de que la señal sea evaluada (por el kernel) en el contexto del proceso de destino. 'kill (2)' es básicamente una comunicación asincrónica muy simple y debe tratarse como tal con todas las implicaciones. –

Respuesta

8

¿El proceso dado por pid siempre se va antes de que la siguiente función entre en acción?

No hay garantía para eso. En un multiprocesador, su proceso puede estar en la CPU 0, mientras que la limpieza en el kernel para el proceso inactivo tiene lugar en la CPU 1. Esa es una condición de carrera clásica. Incluso en procesadores de un solo núcleo no hay garantía de eso.

¿Waitpid siempre devolverá -1 en el caso anterior?

Dado que es una condición de carrera, en la mayoría de los casos, quizás sí. Pero no hay garantía.


Puesto que usted no está interesado en el estado, este SEMICODE podría ser más apropiado en su caso:

// kill all childs 
foreach(pid from pidlist) 
    kill(pid, SIGKILL); 

// gather results - remove zombies 
while(not_empty(pidlist)) 
    pid = waitpid(-1, NULL, WNOHANG); 
    if(pid > 0) 
     remove_list_item(pidlist, pid); 
    else if(pid == 0) 
     sleep(1); 
    else 
     break; 
+0

Gracias por la explicación, no podré usar el código sugerido ya que el controlador SIGCHILD elimina los elementos del pidlist. Eso me deja a la opción: verificar si el proceso se está ejecutando, eliminar si no, matar de lo contrario. – Lekensteyn

+0

Simplemente elimine la bandera 'WNOHANG' y su código funcionará como se espera. –

+0

@Lekensteyn: si ya hay un controlador SIGCHLD que actualiza una lista, este controlador puede llamar a 'waitpid' para eliminar el proceso zombie. Entonces, el ciclo 'while' solo necesita esperar a) todos los procesos muertos y enterrados o b) algún tiempo de espera por seguridad. –

4

El manejador de la señal KILL se ejecutará durante el tiempo de los procesos de la CPU matado. Esto es potencialmente mucho más tarde que su llamada waitpid, especialmente en un sistema cargado, por lo que waitpid bien puede devolver 0.

Cuestiones relacionadas