2010-03-07 17 views
6

He leído sobre fork y, según tengo entendido, el proceso se clona pero ¿qué proceso? ¿El script en sí o el proceso que lanzó el script?¿Qué sucede cuando un proceso se bifurca?

Por ejemplo:

estoy corriendo rTorrent en mi máquina y cuando se completa un torrente, tengo un script que se ejecuta en contra de ella. Este script obtiene datos de la web, por lo que tarda unos segundos en completarse. Durante este tiempo, mi proceso rtorrent está congelado. Así que hice el tenedor script con el siguiente

my $pid = fork(); 
if ($pid == 0) { blah blah blah; exit 0; } 

Si me quedo este script desde la línea de comandos, se trata de volver a la cáscara dentro de un segundo mientras se ejecuta en segundo plano, tal y como era mi intención. Sin embargo, cuando lo ejecuto desde rTorrent, parece ser aún más lento que antes. Entonces, ¿qué fue exactamente bifurcado? ¿El proceso rtorrent se clonó a sí mismo y mi script se ejecutó en eso, o mi script se clonó a sí mismo? Espero que esto tenga sentido.

+1

Comience por publicar un fragmento de Perl que funcione. –

+2

Intenta ejecutar rTorrent in strace y comprueba qué está bloqueando cuando se ejecuta el script. Eso podría dar una pista. Estaba pensando que podría haber sido esperar() en el proceso de nieta, pero parece que el comportamiento en realidad no es posible usando llamadas al sistema tradicional. – jdizzle

Respuesta

2

Para responder a la pregunta nominal, ya que comentó que la respuesta aceptada no lo hace, fork afecta el proceso en el que se llama.En su ejemplo de rTorrent generando un proceso de Perl que luego llama al fork, es el proceso de Perl el que está duplicado, ya que fue el proceso de Perl el que llamó al fork.

En el caso general, no hay forma de que un proceso fork tenga otro proceso que no sea el mismo. Si fuera posible decir que otro proceso arbitrario va al fork, eso abriría un sinfín de problemas de seguridad y rendimiento.

+2

Además de abrir la posibilidad de muchos chistes: "¡oye! ¡Vete a la bifurcación!" "¡No, tenedor!" – Ether

6

La función fork() devuelve DOS VECES! Una vez en el proceso principal y una vez en el proceso hijo. En general, ambos procesos son IDÉNTICOS en todos los sentidos, como si CADA uno acabara de regresar de fork(). La única diferencia es que en uno, el valor de retorno desde fork() es 0, y en el otro es distinto de cero (el PID del proceso secundario).

De modo que cualquiera que sea el proceso que esté ejecutando su script Perl (si es un intérprete Perl integrado dentro de rTorrent entonces rTorrent sería el proceso) se duplicaría exactamente en el punto donde ocurrió el fork().

+0

No creo que esto realmente esté dirigiendo su pregunta ... – jdizzle

+2

@jdizzle - Probablemente porque la pregunta no tiene mucho sentido, porque 'alguien' no entiende el proceso y bifurca ideas. Explicar algunos hechos podría ayudar :) – viraptor

+1

@viraptor - Siento que alguien tiene una buena comprensión de la horquilla() ing. La pregunta es realmente acerca de la implementación de rTorrent. – jdizzle

3

Todo el proceso que contiene las horquillas del intérprete. Afortunadamente, la memoria es copy-on-write, por lo que no es necesario copiar toda la memoria del proceso para bifurcar. Sin embargo, cosas como los descriptores de archivos permanecen abiertos. Esto permite que los procesos secundarios los manejen, pero puede causar problemas si no se cierran adecuadamente. En general, fork() no debe usarse en un intérprete incrustado excepto bajo coacción extrema.

+0

Meh. No es como si este fuera el fin del mundo para fork() en perl en la máquina de un usuario final. Estoy de acuerdo en que probablemente sea una mala práctica usarla con frecuencia (ya que es un buen momento para un cuello de botella). – jdizzle

+0

Si es una mala práctica, ¿existe un método alternativo para evitar el bloqueo? – somebody

2

Mi consejo sería "no hagas eso".

Si el intérprete de Perl está incrustado en el proceso rtorrent, seguramente habrá bifurcado todo un proceso interno, cuyos efectos probablemente estén mal definidos en el mejor de los casos. En general, es una mala idea jugar con material de nivel de proceso en un intérprete incorporado independientemente del idioma.

Existe una gran posibilidad de que algún tipo de bloqueo no se libere correctamente o de que los procesos se desarrollen de forma no intencionada y posiblemente en competencia.

+0

¿Qué tan común es vincular realmente con el intérprete de Perl? ¿No sería mucho más práctico (y seguro) para el sistema() este tipo de llamadas? – jdizzle

+0

Es cierto que llamar 'fork()' en un programa de subprocesos múltiples es un problema. Sin embargo, si restringe lo que sucede en el proceso secundario, no es tan malo. Por ejemplo, no llame a nada que necesite adquirir un bloqueo en modo de usuario. Pero el uso típico de los siguientes 'fork()' con 'dup2()', 'close()', 'execve()' etc. debería ser seguro. – asveikau

+0

@jdizzle: La vinculación con un intérprete externo, Perl o de otro modo, es muy común, pero no queda del todo claro a partir de la pregunta si ese es el caso o no con este programa. Sin embargo, al volver a leer, es posible que tenga razón en que se está utilizando el sistema(). –

4

Creo que he encontrado el problema mirando a través de la fuente de rTorrent. Para algunos procesos, leerá toda la salida enviada a stdout antes de continuar. Si esto le sucede a su proceso, rTorrent bloqueará hasta que cierre el proceso estándar. Como está bifurcando, su proceso hijo comparte el mismo estándar que el padre. Su proceso principal se cerrará, pero el conducto permanecerá abierto (porque su proceso hijo aún se está ejecutando). Si hicieras un esfuerzo de rTorrent, apostaría a que se bloquearía en esta llamada read() mientras ejecutas tu comando.

Intente cerrar/redireccionar stdout en su script perl antes del fork().

+0

Resuelve el problema, pero no responde la pregunta nominal. Me gustaría eso. – darch

+0

@darch - el título de la pregunta es realmente relevante para el problema que alguien está tratando de resolver – jdizzle

+0

Lo encontré muy útil, así que gracias por ponerlo aunque "no respondió la pregunta nominal", @jdizzle :) –

1

Cuando creamos un proceso usando fork, el proceso hijo tendrá la copia del espacio de direcciones. Así que el niño también puede usar el espacio de direcciones. Y también puede acceder a los archivos que abre el padre. Podemos tener el control sobre el niño. Para obtener el estado completo del niño, podemos usar wait.

Cuestiones relacionadas