Procesos en Linux, estados y prioridades
Hoy aprenderemos los conceptos de gestión de los procesos en linux y las herramientas
para administrar listas de procesos y prioridades.
Los procesos en Linux, o en cualquier sistema operativo *nix, son creados en base a un
proceso ya existente mediante un mecanismo de clonación, o «fork«. Hoy hablaremos
específicamente de gestión de procesos en linux.
Un proceso en Linux genera un nuevo proceso para que realice una tarea determinada, y
este nuevo proceso es considerado proceso «hijo» del proceso anterior, al que llamaremos
«padre«.
Esta estructura de procesos padres e hijos forman un árbol jerárquico de procesos, en los
que podemos distinguir a hilos del kernel, al proceso init, y al resto de los procesos del
sistema, descolgados de algún otro proceso, lo que nos da una idea de qué proceso generó a
cuál otro.
Un ejemplo de la estructura jerárquica podemos verlo con ps o pstree:
diego@cryptos:~$ ps fax
PID TTY STAT TIME COMMAND
[...]
262 ? S< 0:00 \_ [kpsmoused]
405 ? S 0:10 \_ [jbd2/sda5-8]
406 ? S< 0:00 \_ [ext4-rsv-conver]
408 ? S< 0:00 \_ [kvm-irqfd-clean]
21776 ? S< 0:00 \_ [dio/sda5]
10261 ? S 0:00 \_ [kworker/3:2]
10268 ? S 0:00 \_ [kworker/1:2]
10277 ? S 0:00 \_ [kworker/2:2]
14024 ? S 0:00 \_ [irq/31-mei_me]
14025 ? S 0:00 \_ [kworker/2:0]
14034 ? S 0:00 \_ [kworker/3:0]
14038 ? S 0:00 \_ [kworker/1:1]
23538 ? S 0:00 \_ [kworker/0:0]
23767 ? S 0:00 \_ [kworker/u8:0]
24313 ? S 0:00 \_ [kworker/u8:2]
24395 ? S 0:00 \_ [kworker/0:1]
24591 ? S 0:00 \_ [kworker/u8:1]
24655 ? S 0:00 \_ [kworker/1:0]
24742 ? S 0:00 \_ [kworker/3:1]
24755 ? S 0:00 \_ [kworker/0:2]
1 ? Ss 0:02 /sbin/init
195 ? Ss 0:00 /usr/lib/systemd/systemd-journald
229 ? Ss 0:00 /usr/lib/systemd/systemd-udevd
423 ? Ss 0:01 /usr/bin/dbus-daemon --system --
address=systemd: --nofork --nopidfile --systemd-activation
426 ? Ss 0:00 /usr/lib/systemd/systemd-logind
506 ? Ss 0:00 login -- diego
516 tty1 Ss+ 0:00 \_ -bash
549 tty1 S+ 0:00 \_ xinit /home/diego/.xinitrc --
/etc/X11/xinit/xserverrc :0 vt1 -auth /tmp/serverauth.
550 tty1 S 101:04 \_ /usr/lib/xorg-server/Xorg -
nolisten tcp :0 vt1 -auth /tmp/serverauth.294QcjxI77
553 tty1 Sl 0:01 \_ /usr/bin/lxsession -s LXDE -e LXDE
585 tty1 S 0:42 \_ openbox --config-file
/home/diego/.config/openbox/[Link]
587 tty1 Sl 0:00 \_ lxpolkit
588 tty1 Sl 4:24 \_ lxpanel --profile LXDE
1006 tty1 Sl 1063:25 | \_ firefox
1681 tty1 Sl 30:31 | \_ /usr/lib/chromium/chromium
1683 tty1 S 0:00 | | \_
/usr/lib/chromium/chrome-sandbox /usr/lib/chromium/chromium --type=z
1684 tty1 S 0:00 | | | \_
/usr/lib/chromium/chromium --type=zygote
1686 tty1 S 0:00 | | | \_
/usr/lib/chromium/chrome-sandbox /usr/lib/chromium/nacl_help
1687 tty1 S 0:00 | | | | \_
/usr/lib/chromium/nacl_helper
1689 tty1 S 0:00 | | | \_
/usr/lib/chromium/chromium --type=zygote
1755 tty1 Sl 0:04 | | | \_
/usr/lib/chromium/chromium --type=renderer --force-field
1761 tty1 Sl 0:08 | | | \_
/usr/lib/chromium/chromium --type=renderer --force-field
1815 tty1 Sl 7:09 | | | \_
/usr/lib/chromium/chromium --type=renderer --force-field
[...]
PID, el identificador de proceso en Linux
El PID es un número entero que identifica unívocamente a cada proceso en una tabla de
procesos administrada por el kernel Linux. Esta tabla de procesos mantiene una entrada por
cada uno de los procesos que están en ejecución en el sistema en el momento actual. Esa
tabla es, precisamente, la que se consulta con comandos como ps o pstree.
Uno de los datos almacenados, es el pid, o process-id, utilizado, como hemos visto en un
artículo anterior, para facilitarnos la terminación de procesos que no responden, o para que
el sistema operativo pueda comunicar procesos usando IPC, entre otras tareas.
Kernel Multitarea
El kernel Linux es un kernel de sistema operativo que permite la multitarea. Hay que tener
en cuenta que el procesador solamente puede estar procesando un proceso a la vez en cada
uno de sus núcleos, o «cores».
¿Cómo logra Linux simular la multitarea? ¿Cómo es posible, de esta forma, que podamos
estar ejecutando varias aplicaciones «simultáneamente» con un solo core?
La respuesta es simple. El kernel del sistema operativo le da un tiempo de procesamiento a
un proceso, luego lo retira de los registros del procesador, e introduce a otro proceso en su
lugar. Este intercambio se lleva a cabo con una frecuencia altísima que permite simular una
multitarea real a nivel de usuario.
El estado de los procesos en Linux
En Linux los procesos pueden estar en diferentes estados, simbolizados mediante una letra
en la salida del comando htop/top.
Los estados principales en los que un proceso puede estar, y que en la salida de un htop
están etiquetados en la columna «S»(status), son los siguientes:
D Uninterruptible sleep – Espera ininterrupible, generalmente el proceso se
encuentra esperando una operación de entrada/salida con algún dispositivo.
R Running – Corriendo, el proceso se encuentra corriendo en el procesador.
S Interruptible sleep, espera interrumpible, el proceso se encuentra esperando a
que se cumpla algún evento, por ejemplo, que el planificador de procesos del kernel
lo planifique para su ejecución.
T Stopped, detenido, un proceso que ha sido detenido mediante el envío de
alguna señal generalmente.
Z Defunct (“zombie”) process, proceso terminado, pero cuyo padre aún sigue
«vivo» y no ha capturado el estado de terminación del proceso hijo, y por
consiguiente, no lo ha eliminado de la tabla de procesos del sistema. En definitiva,
un proceso zombie es un proceso que «murió», pero «sigue estando» en la tabla de
procesos del sistema. En algún otro artículo hablaremos específicamente de estados
de procesos, zombies, y cómo detectarlos.
Procesos en Linux y prioridades
Ahora bien, cuando el kernel, mediante su administrador de procesos, retira un proceso del
procesador, ¿cómo decide qué proceso deberá ingresar?
Eso lo decide mediante un cálculo de prioridades. Todos los procesos en linux corren con
determinada prioridad, un número entero, que puede verse en la salida de un comando top o
htop.
La tercer columna, etiquetada como PRI(ority) hace referencia a esta prioridad, por
defecto, 20.
Ese 20 hace referencia a una prioridad media por defecto. Las prioridades de procesos de
usuario se numeran desde 0 a 39. Mientras menor es el número, más alta será la prioridad,
por lo que una prioridad cercana a 0 indicará mayor prioridad, y el proceso que la posea
tendrá más chances de ser planificado en el procesador, que uno que tenga una prioridad
más baja, cercana al 39.
La columna NI(ce) hace referencia a una prioridad relativa que por lo general mapea con
la prioridad absoluta PRI, y que depende del estado y carga de procesamiento, pero que va
desde -20 a +19, donde -20 es la mayor prioridad de proceso de usuario (equivalente a un
PRI de 0) y +19 es la menor prioridad de usuario (equivalente a un PRI de 39), siendo el NI
de 0 la prioridad media, equivalente a un PRI de 20.
RT=Real time?
Como nota adicional, no estamos considerando las prioridades de tiempo real que provee el
núcleo (real time). El total de prioridades de Linux es de 140, desde la prioridad 0 hasta la
prioridad 139. Las 40 que vemos en las herramientas como renice, nice o top/htop, son en
realidad las prioridades que van desde 100 a 139, las prioridades de procesos de usuario.
Las prioridades reales desde la 0 a la 99 son prioridades de tiempo real, no podemos
modificarlas con herramientas de usuario, y, por ejemplo, en top/htop las veremos como
«RT».
Cambiando prioridades de procesos en linux
Si quisiéramos ejecutar una tarea determinada, por ejemplo, alguna tarea que consuma
intensivamente al procesador, y quisiéramos hacerlo con una prioridad menor de lo habitual
de modo que el sistema no se ralentice demasiado, y nos deje «espacio» para trabajar,
podríamos ejecutarla utilizando el comando «nice» de esta forma:
nice -[+|-]nn comando
donde nn es un número positivo o negativo de prioridad, y el comando es la tarea a
ejecutar.
Veamos un ejemplo, vamos a ejecutar el comando «yes > /dev/null &» con una prioridad
baja de +10:
nice -+10 yes > /dev/null &
Y veamos el cambio en la línea marcada en la salida de un htop:
Ahora bien, si por casualidad necesitáramos elevar la prioridad del proceso, supongamos, a
-5 (5 puntos encima de la normal), podremos hacer uso del comando «renice» y utilizando
el PID del proceso, en nuestro caso, 17016, de esta forma:
renice -5 17016
Y la salida del htop nos mostrará el siguiente resultado:
Prioridades en htop y top
En la interfaz de htop podremos presionar F7 o F8 para aumentar o reducir la prioridad de
un proceso respectivamente (siempre que tengamos privilegios, principalmente para
aumentarla). Esto se aplica directamente al proceso que tengamos seleccionado en la
interfaz del htop.
En top deberemos presionar la tecla «r» (renice) para cambiar la prioridad de un proceso.
El top nos pedirá el PID del proceso en cuestión, y luego el número de prioridad a setear.