Curso de Introducción a Unix - por F.C.

PROCESOS

Cada vez que introducimos un comando o un programa, la shell lo ejecuta. Mientras está en memoria ejecutandose se le denomina proceso. Puede haber varios procesos ejecutando un mismo programa. Es decir, existe una sola copia del programa en el file system y cada vez que se ejecuta se crea un proceso.

A cada proceso le corresponde un número llamado PID. Cuando se inicializa el sistema se crea un único proceso perteneciente a root, que a su vez va a crear otros subprocesos en una estructura jerárquica. También al entrar en nuestra cuenta ocurre lo mismo, se crea un proceso del que van a colgar una serie de subprocesos. Cada proceso puede tener muchos subprocesos (child process) y un sólo proceso padre (parent process).

Los procesos que nos pertenecen podemos manipularlos de diferentes formas. Al entrar un comando desde una shell, ésta crea un child process donde se ejcutará el comando. La shell esperará a que se ejecute el comando y cuando esto suceda podemos volver a ejecutar nuevos comandos. La ejecución de comandos de esta manera se le denomina ejecución en el foreground y nos impide usar la shell mientras se ejecuta el comando.

Existe sin embargo otra forma de ejecutar los comandos a la que se le denomina en el background. Para ello se añade al final de la línea de comandos el caracter &. Al introducir el comando nos imprime en la terminal dos números, el primero es el número del trabajo y el segundo el PID asociado al proceso.

Mientras se ejecutan los procesos en el background se puede seguir usando la shell. Si el proceso produce alguna salida por la terminal, la podemos redireccionar para que no interfiera en lo que estemos tecleando en la shell (también se puede redireccionar los errores). Por ejemplo:
du -k > file &

Los procesos que queramos ejecutar en el background no deben ser comandos que esperen a que introduzcamos alguna información desde la shell interactivamente, pues en ese caso el proceso se parará. Se puede solucionar redireccionando la standard input a un fichero que contenga exactamente lo que teclearíamos en línea de comando

Los procesos que ejecutamos en el foregound podemos cancelarlos o también suspenderlos momentaneamente para traerlos nuevamente al foreground o al background.

Para cancelar un proceso utilizamos CTRL-C y Para suspenderlo CTRL-X. Para mandar nuevamente al foreground un proceso suspendido se usa fg, mientras para mandarlo al bacground se usa bg. Podemos traer al foreground un proceso ejecutado en el background con el comando:
fg job_number
donde job_number es el número del trabajo, no el PID. Para ver el estado en que se encuentran los procesos en el background utilizamos el comando jobs que nos dará el número y el estado de cada proceso en el background. Con la opción -l también nos dará el PID.

Controlando los procesos

Hay varios comandos que permiten obtener información de los procesos que se están ejecutando. Los más útiles son ps y top que veremos ahora con algo más de detalle.

ps

Nos da información sobre el estado de los procesos y tiene una gran variedad de opciones. Si lo ejecutamos sin opciones nos muestra información sobre nuestros procesos asociados al terminal. La salida muestra el PID, el terminal, el tiempo de CPU utilizado y el nombre del comando.

Con la opción -a se muestran los procesos que son requeridos más frecuentemente, y no sólo los procesos asociados a un terminal. La opción -e muestra información de todos los procesos que se están ejecutando. Para obtener información más detallada están las opciones -f y -l. Parte de la información que suministran es la siguiente (se incluye entre parentesis a que opción corresponde):

UID     (f,l)   Nombre del usuario
PID     (f,l)   Número de identificación del proceso
PPID    (f,l)   Número de identificación del proceso padre
STIME   (f)     La hora de comienzo del proceso
TTY     (f,l)   El terminal 
TIME    (f,l)   Tiempo de CPU
CMD     (f,l)   El nombre del comando
S       (l)     El estado del proceso
PRI     (l)     La prioridad del proceso
NI      (l)     El valor de nice para  calcular la prioridad
ADDR    (l)     La dirección de memoria del proceso
SZ      (l)     La cantidad de memoria que esta ocupando

Los posibles estados de un proceso son:

O       El proceso se está ejecutando en el procesador
S       (sleeping) El proceso está esperando por un suceso
        para terminar
R       (runnable) El proceso está en la cola de ejecución
I       Indica que el proceso está siendo creado
Z       (zombie) El proceso ha terminado y el proceso padre 
        no está esperando
T       El proceso está parado por una señal del proceso padre
X       El proceso está esperando por más memoria
top

Nos muestra y actualiza periodicamente información sobre los procesos que más tiempo de CPU utilizan. Además muestra información sobre el estado del sistema como: El último PID. Un promedio del número de trabajos en la cola de ejecución. El número de procesos y cuantos se hayan en cada estado. El porcentaje de tiempo que usa la CPU en diferentes estados. Información sobre la memoria del sistema.

La información de los procesos que se ofrece es:

PID
USERNAME
PRI
NICE
SIZE
RES
STATE
TIME
CPU
COMMAND

Con significados similares a los de ps. Las diferencias son SIZE y RES que representan el tamaño real del proceso y la parte residente en memoria respectivamente. CPU es una estimacion del porcentaje de tiempo de CPU usado.

Prioridades

La CPU tiene que compartir su tiempo entre los distintos procesos. El cálculo de la prioridad que tiene un proceso lo hace el kernel y se basa en varios factores como el tiempo de CPU que ha usado recientemente, el estado del proceso (si está esperando que introduzcamos un dato o está listo para ser ejecutado) y el valor de nice del proceso.

Cada proceso tiene un valor de nice que varia entre -20 y 20. Cuanto más bajo mayor prioridad tendrá el proceso.

Los procesos normalmente heredan de sus procesos padres la prioridad. Los usuarios sólo pueden tener procesos con nice 0 o mayor, mientras que el super-user puede tener procesos con valores menores. Por defecto los usuarios en la consola van a tener procesos con una prioridad de 0. Podemos lanzar procesos con menor menor prioridad o bajar la prioridad de procesos que ya se están ejecutando, pero nunca podremos aumentar la prioridad a un proceso, aunque previamente se la hubieramos bajado, sólo el super-user puede hacer esto.

El valor de nice lo podemos ver con ps o top ( el primero nos lo muestra de 0 a 40 y el segundo de -20 a 20).

Para ejecutar un proceso con menor prioridad se usa el comando:
nice -n comando
n es el incremento que le damos al valor de nice y por tanto no podra ser mayor que 20. Si no damos valor a n, se asume un valor de 4.

Para bajar la prioridad de un proceso se ejecuta el comando:
renice n PID
n es el valor de nice que vamos a dar al proceso que tendrá que ser mayor que el valor que tenga el proceso. PID es el número identificador del proceso.

Hay varias razones para lanzar procesos con menor prioridad. La principal es que con ello se evita que un proceso pueda acaparar el tiempo de la CPU haciendo que la máquina vaya muy lenta al trabajar de forma interactiva. En la red del IAC, cuando ejecutamos procesos en una máquina en la que no estamos trabajando en la consola, nice tendrá un valor de 10 para que el usuario que trabaja en consola tenga preferencia y pueda trabajar interactivamente.

Matando procesos

Cuando queremos teminar un proceso tenemos varias formas de hacerlo. La más sencilla es utilizar CTRL-C, si el proceso esta en el foreground.

Un proceso en el background podemos matarlo con el comando kill. Por ejemplo:
kill %2
mata el proceso que tiene como número de trabajo el 2 (no el PID).

Para matar un proceso cualquiera utilizamos:
kill PID
que tendría el mismo efecto que utilizar CTRL-C

Si esto no funciona podemos usar:
kill -1 PID
que tendría un efecto sobre el proceso igual a que si nos salimos de la cuenta, e intentará además matar todos los subprocesos que cuelgan de él.

Si esto tampoco funciona se usa:
kill -9 PID
que matará el proceso (aunque es posible que queden subprocesos).

Lanzando procesos a determinadas horas

Es posible lanzar procesos de forma que se empiecen aejecutar a una determinada hora. Por ejemplo si vamos a ejecutar procesos que van a utilizar mucho tiempo de CPU, es aconsejable hacerlo de forma que se ejecuten por la noche, cuando normalmente habrá menos usuarios y evitaremos colapsar las máquinas. Es posible hacerlo de forma que se ejecuten periodicamente o simplemente hacer una cola de comandos que se van ejecutando secuencialmente cuando el nivel de carga del sistema lo permite.

Los comandos para hacer esto son at, batch y crontab.

at Nos permite especificar el momento en que queremos ejecutar los comandos. Si los procesos producen una salida por pantalla o se producen errores nos envía un mail. Podemos especificar la hora con una gran variedad de formatos. Algunos ejemplos que no requieren mayor explicación son:

at 0815am Jan 24
at 8:15am Jan 24
at now + 1 day
at now next day
at 5 pm Friday

Una vez introducido el comando, at nos cambia el prompt a:
at>
Entonces empezamos a teclear los comandos y cuando hayamos terminado salimos con CTRL-Z.

El comando batch es similar a at, sólo que no indicamos cuando ejecutar los comandos. Al ejecutar el comando batch nos cambiará directamente al prompt at> donde tecleamos los comandos. Al salir con CTRL-Z empezarán a ejecutarse los comandos.

crontab

Este comando sirve para crear, modificar o borrar un fichero donde cada usuario define una serie de comandos que quiere que se ejecuten periodicamente o en determinadas fechas. Estos ficheros no están en nuestro home o cualquier otro directorio que nos pertenezca, sino que estan en un directorio donde se encuentran todos los crontabs de los usuarios del sistema. Las tablas dependen de la máquina, es decir un usuario puede tener una tabla en cada máquina y cada máquina sólo ejecuta los comandos de la tabla creada en ella.

Estas tablas tienen un formato definido. Son seis columnas separadas por espacios o Tab. La primera columna corresponde a los minutos. La segunda corresponde a las horas. La tercera al dia del mes. La cuarta al mes. La quinta al dia de la semana. La sexta el comando a ejecutar. Por ejemplo

#ejemplo de crontab
#min    hora    dia     mes     dia     comando 
#0-59   0-23    1-31    1-12    0-6
0       11,18   *       *       1-5     cat sound.au>dev/audio
0       4       *       *       *       cp -r /scratch/tesis /scratch2

Los comandos se ejecutarán cuando la hora y fecha coincida con las indicadas en la tabla. En cada columna pueden indicarse varios valores separados por comas, dar rangos con números separados por el signo menos, o pueden tener un asterisco que indica cualquier valor. Los dias pueden indicarse por el dia del mes o de la semana, si se indican valores para los dos el comando se ejecutará cuando se cumpla que la fecha coincida con cualquiera de los dos (por ejemplo indicar que se ejecute el primero de mes y todos los sabados). Si queremos definir el dia bien por el mes o bien por la semana, ponemos un asterisco en el que no vamos a utilizar.

El comando crontab tiene varias opciones:
crontab filename
Copia el fichero filename como la tabla crontab. Las modificaciones que hagamos en filename no tendrán efecto hasta que no ejecutemos el comando.
crontab -e
Permite editar la crontab que tengamos definida.
crontab -l
Permite ver la crontab que tengamos definida.
crontab -r
Borra la crontab.