fork
, esta genera un duplicado
del proceso actual. El duplicado comparte los valores actuales
de todas las variables, ficheros y otras estructuras
de datos. La llamada a fork
retorna
al proceso padre
el identificador del proceso
hijo
y retorna un cero al proceso hijo.
Las siglas PID, del inglés Process IDentifier, se usan para referirse al identificador de proceso.
El hijo puede obtener el identificador del proceso padre llamando a la función getppid. La variable especial $$ contiene el PID del proceso. Es de sólo lectura.
Veamos un ejemplo de uso de estas funciones:
#!/usr/local/bin/perl5.8.0 -w print "PID=$$\n"; my $child = fork(); die "Falló el fork: $!" unless defined $child; if ($child > 0) { # proceso padre print "Aqui proceso padre: PID=$$, hijo=$child\n"; } else { #proceso hijo my $ppid = getppid(); print "Aqui proceso hijo: PID=$$, padre=$ppid\n"; }La variable
$$
contiene el identificador de proceso
actual. Veamos un ejemplo de ejecución:
> fork.pl PID=27087 Aqui proceso padre: PID=27087, hijo=27088 Aqui proceso hijo: PID=27088, padre=1Los procesos hijo pueden a su vez generar nuevos hijos, creandose así una jerarquía de procesos. dicha jerarquía recibe el nombre de grupo de procesos. Todos los miembros de un grupo comparten los ficheros que estaban abiertos cuando su padre los creó. En particular comparten
STDIN
, STDOUT
y STDERR
.
Obsérvese la segunda línea de salida: el hijo no alcanza
a escribir el PID del proceso padre.
El padre ha finalizado primero
cerrando STDOUT. Es necesario sincronizar ambos procesos.
Para ello es posible usar bien la función wait
bien la función waitpid:
$ cat -n forkw.pl 1 #!/usr/bin/perl -w 2 use strict; 3 4 print "PID=$$\n"; 5 6 my $child = fork(); 7 die "Falló el fork: $!" unless defined $child; 8 9 if ($child > 0) { # proceso padre 10 print "Aqui proceso padre: PID=$$, hijo=$child\n"; 11 waitpid $child, 0; 12 } else { #proceso hijo 13 my $ppid = getppid(); 14 print "Aqui proceso hijo: PID=$$, padre=$ppid\n"; 15 exit 0; 16 }En muchos sistemas Unix, una vez que se ha realizado el
fork
,
si el proceso hijo termina antes que
lo haga el padre
el proceso hijo no desaparece totalmente sino que queda
en un estado conocido como zombie.
El zombie permanece en la tabla de procesos
con el único objeto de entregar su estatus de salida
al proceso padre por si este pregunta por el usando wait
o waitpid. Este proceso se denomina reaping (segar).
Si el proceso padre se ramifica en un gran número de hijos
y no siega es posible que la tabla de procesos
se llene de procesos zombis. Por tanto, todo programa que llama
a fork
debe segar sus hijos llamando a wait o
waitpid.
La función wait tiene el formato
$pid = wait()La función hace que el proceso espere por la finalización de cualquier hijo y retorna el PID del proceso hijo. El proceso se bloquea hasta que exista un hijo que termine. Se puede consultar el código de terminación examinando la variable especial $?. Un código 0 indica una salida normal.
La función waitpid tiene el formato
$pid = waitpid($pid, $flags)En este caso se espera por el hijo especificado en
$pid
.
Es posible usar un argumento $pid
igual a para indicar
que se espera por cualquier proceso (a la wait
).
La conducta de waitpid
pude modificarse mediante
el uso del argumento $flags
.
Hay un buen número de constantes definidas en el grupo
:sys_wait_h del módulo estandar POSIX.
Estas constantes se utilizan combinandolas con un OR
binario.
La más usada es WNOHANG
la cual hace que el proceso
no se bloquee (útil si se quiere hacer polling).
La función retorna el PID del proceso o si no existe ninguno
disponible (cuando se usa la versión sin bloqueo).
Otra constante es WUNTRACED la cual le indica a
waitpid
que además de los hijos que hayan terminado también recolecte
los hijos parados mediante una señal de STOP o TSTP.