Identificación de procesos: todos los procesos tienen un número identificativo único (PID = Process Identification).
Además, existe otro tipo de información asociada al proceso:
ps
.
Por ejemplo, para ver qué procesos estoy corriendo en estos
momentos, puedo usar:
<T>/usuarios/gyermo$ ps -fu gyermo UID PID PPID C STIME TTY TIME COMMAND gyermo 7998 7984 7 12:19:33 pts/td 0:00 ps -fu gyermo gyermo 7984 7983 1 12:19:25 pts/td 0:00 -kshEl identificador de proceso aparece en la columna PID. Este número caracteriza al proceso de forma unívoca. Podemos ver que estoy ejecutando dos procesos, el correspondiente al propio
ps
y el asociado a la shell (el programa que
admite órdenes del teclado y las ejecuta).
kill
n, donde n es el PID del proceso que queréis
matar. Si el proceso no se muere así, podéis intentar matarlo
con kill -9
n, pero sólo después de haberlo intentado
de la forma anterior.
Creación de procesos en UNIX: los procesos nuevos se crean por "clonación" de los procesos antiguos:
Aunque son dos procesos iguales, cada uno continúa su ejecución de modo independiente. Esto es debido a que la función fork() devuelve un valor distinto a cada proceso:
fork()
devuelve:printf
es para que cada proceso imprima
su identificador de usuario. Por ejemplo:
713: soy el padre. 1022: soy el hijo.Añadid, al final, del programa la orden
sleep(60);
,
incluyendo el fichero de cabecera que sea necesario. Ejecutad
el programa en segundo plano para que podáis seguir
tecleando aunque el programa se ejecute y dad la orden
ps
apropiada para ver en ejecución tanto al
padre como al hijo.
&
. Esto hace que retoméis
el control inmediatamente y no tengáis que esperar a que
el programa arrancado acabe. Probad la diferencia entre:
sleep 20y
sleep 20 &
Un proceso puede cambiar el programa que está ejecutando mediante la llamada al sistema
execve():#include <unistd.h>
int execve (const char *nomfich, const char *argv[],
const char *envp[]);
El procedimiento habitual para crear un nuevo proceso es llamar primero a
fork y, el nuevo hijo, que llame a execve. No sólo disponéis deexecve
para que un proceso
deje definitivamente lo que está haciendo y pase a ejecutar
otro programa. También existen otras funciones de la misma
familia que permiten especificar los parámetros que se le
pasan al nuevo programa de diferentes maneras o que realizan
una búsqueda del programa por el PATH del usuario. Estas funciones
las podéis encontrar en el resumen.
exec
,
haced un programa que ejecute un ls -l
mediante
una llamada al sistema de esa familia.
main
y devolver valores
al Sistema Operativo mediante el valor devuelto por
main
.
exec
, los
argumentos que recibirá la función main
del nuevo
programa son los especificados en los parámetros de la llamada
exec
.
fork
, el valor que devuelve la función
main
ya no es devuelto al Sistema Operativo, sino
que es devuelto a su proceso padre. Para que el proceso padre
pueda recibir ese código de retorno del hijo, ha de efectuar
una llamada al sistema wait
, cuyo prototipo es:
pid_t wait(int *stat_loc);Esta llamada al sistema nos devuelve un tipo de datos específico, que será un entero, donde se especificará el error, si se produce, o el PID del proceso hijo a que corresponde la información suministrada por la llamada.
<sys/types.h>
. Por ejemplo, para saber el
código de retorno de un hijo, podríamos hacer:
#include <sys/types.h> [...] int valor_devuelto; pid_t pid; [...] pid=wait(&valor_devuelto); [... comprobación de errores estándar ...] if (WIFEXITED(valor_devuelto)) printf("El valor devuelto por el proceso de PID %d es %d.\n",pid,WEXITSTATUS(valor_devuelto));
wait
tiene una llamada prima hermana denominada
waitpid
. Su prototipo es:
pid_t waitpid(pid_t pid, int *stat_loc, int options);Como podéis ver en el resumen, los dos parámetros que se añaden a la función son el primero, que permite especificar el PID en concreto sobre el que deseamos conocer su información, y el último, que es un campo de bits que permite especificar opciones. De todas las opciones, sólo nos interesará
WNOHANG
.
wait
y waitpid
,
son el primer ejemplo de llamadas al sistema que disponen de una
versión bloqueante y no bloqueante. Recordemos el diagrama de
estados de UNIX:Diagrama de estados en UNIX:
wait
y esta información no está disponible, el proceso abandona el
estado de listo y pasa al estado de dormido (bloqueado). Este
estado se caracteriza porque el proceso no consume CPU, es
decir, no sustrae tiempo de cálculo a otros procesos. Cuando
la información está disponible, el proceso se desbloquea y
continúa su ejecución. A efectos del programador, el programa
se para en la llamada al sistema hasta que la información esté
disponible.
waitpid
tiene una
versión no bloqueante y otra, bloqueante. Todo depende de
si especificamos WNOHANG
(no bloqueante) o no
lo especificamos (bloqueante) en su tercer parámetro.
waitpid(-1,&valor_devuelto,0);
while (waitpid(-1,&valor_devuelto,WNOHANG)==0)
/* espera ocupada */;
sleep
. El proceso padre esperará a que el hijo
concluya mediante waitpid
. Haced una versión
bloqueante y otra no bloqueante y ved la diferencia ejecutando
el programa en segundo plano y monitorizando su comportamiento
mediante la orden ps
.
wait(&a)
es equivalente a
waitpid(-1,&a,0)
. waitpid
es
una llamada que incluye, como caso particular, a
wait
.
wait
para recoger su
código de retorno (valor devuelto al Sistema Operativo).
ps
.
init
, que se encarga de
"exorcizarlo".
Soy un proceso nieto1 (PID=23840). Mi suma es 0. Soy el proceso padre (PID=23803). Mi suma es 21.Al acabar, el proceso devuelve un código de retorno igual a la suma previamente calculada. De este modo, el padre de todos los procesos conocerá la suma de las últimas cifras del PID de todos sus descendientes, incluído él mismo.
ps
&
ksh
jobs
exec
system
sleep
exec
?execl
hay que ponerle NULL
como último
parámetro? Me parece una bobería.[...] int resultado; pid_t pid; [...] sleep(5); pid=getpid(); if((waitpid(pid, &resultado, WNOHANG)) == -1){ perror("wait"); return 1; }me da el siguiente error:
wait:no child proccessNo lo entiendo porque he hecho un
fork()
antes y ya he tomado la precaución de esperar cinco
segundos para que al hijo le dé tiempo a nacer.