1. Qué es un estado
El estado de un proceso es la situación en la que se encuentra en un instante dado, desde el punto de vista del planificador: si está esperando ser admitido, si está listo para ejecutarse, si está usando la CPU, si está esperando un evento o si ya terminó. El estado determina en que cola del sistema está el proceso y que puede hacer el núcleo con él.
El estado es uno de los campos del PCB, como viste en el tema 4. Cambia a lo largo de la vida del proceso, y cada cambio es una transición que el núcleo registra en el PCB. Por eso, cuando preguntas «¿en que estado está este proceso?», el núcleo no necesita adivinar: solo lee el campo state del task_struct.
El estado no es lo mismo que la actividad del programa. Un proceso puede estar «listo» sin estar haciendo nada útil, o «bloqueado» esperando el disco mientras su código está perfectamente válido. El estado describe la relación del proceso con el sistema operativo, no lo que hace el programa.
Piensa en el estado como la posición de un cliente en un sistema de atención: esperando en la puerta (nuevo), en la fila de espera (listo), siendo atendido (en ejecución), esperando que llegue un documento (bloqueado) o ya atendido y retirado (terminado). El estado dice en que cola está, no que está pensando el cliente.
2. Los cinco estados clásicos
El modelo clásico de estados de un proceso, el que aparece en los libros de texto y en la mayoría de los sistemas operativos, tiene cinco estados:
| Estado | Nombre en inglés | Que significa |
|---|---|---|
| Nuevo | New | El proceso acaba de crearse. El núcleo está preparando su PCB, su espacio de direcciones y sus recursos, pero aún no lo ha admitido en el sistema. No puede ejecutarse. |
| Listo | Ready | El proceso está preparado para ejecutarse: tiene todo lo que necesita (memoria, recursos) y solo espera que el planificador le asigne la CPU. Está en la cola de listos. |
| En ejecución | Running | El proceso está usando la CPU en este momento. En un sistema con un solo núcleo, solo un proceso puede estar en este estado a la vez. |
| Bloqueado | Waiting / Blocked | El proceso no puede ejecutarse porque está esperando que ocurra algo: que termine una operación de E/S, que llegue un dato de la red, que se libere un recurso, que expire un temporizador. Está en una cola de espera. |
| Terminado | Terminated / Exit | El proceso terminó su ejecución (con exit o por una señal). El núcleo libera sus recursos, pero el PCB puede quedar un tiempo como zombi hasta que el padre lo recoge. |
Estos cinco estados son suficientes para describir la vida de un proceso en la mayoría de los casos. Pero hay matices, como la suspensión, que veremos más adelante.
3. El diagrama de estados
Los cinco estados se conectan por transiciones que el núcleo dispara en respuesta a eventos. El diagrama clásico es este:
Las transiciones son las flechas del diagrama. Cada una corresponde a un evento concreto que el núcleo detecta y procesa. Veámoslas una por una.
4. Las transiciones en detalle
admit (Nuevo → Listo)
Cuando un proceso se crea (con fork o equivalente), el núcleo lo pone en estado «nuevo» mientras prepara su PCB y su espacio de direcciones. Una vez que todo está listo, lo admite al sistema: lo mueve a «listo» y lo pone en la cola de listos. En la práctica, esta transición es muy rápida y casi inmediata.
dispatch (Listo → En ejecución)
El planificador elige un proceso de la cola de listos y le asigna la CPU. El núcleo hace un cambio de contexto: guarda el estado del proceso que se estaba ejecutando (si lo había) y carga el del elegido. A partir de ese momento, el proceso está «en ejecución».
timeout (En ejecución → Listo)
En los sistemas con tiempo compartido, un proceso no puede usar la CPU indefinidamente. El núcleo le asigna un cuanto de tiempo (típicamente unos milisegundos). Cuando el cuanto expira, el núcleo interrumpe al proceso, lo mueve de «en ejecución» a «listo» y lo pone de nuevo en la cola de listos. Es una transición involuntaria: el proceso no la pide.
event wait (En ejecución → Bloqueado)
Cuando un proceso en ejecución necesita esperar algo (leer del disco, recibir datos de la red, esperar a un hijo, adquirir un recurso), llama a una operación que lo bloquea. El núcleo lo mueve a «bloqueado» y lo pone en la cola de espera correspondiente. El proceso deja la CPU, que se asigna a otro.
event occurs (Bloqueado → Listo)
Cuando el evento que el proceso esperaba ocurre (los datos llegaron, el disco terminó, el hijo terminó), el núcleo lo despierta: lo mueve de «bloqueado» a «listo» y lo pone en la cola de listos. El proceso aún no se ejecuta: solo está listo para cuando le toque el turno.
release (En ejecución → Terminado)
Cuando un proceso termina (con exit, return en main, o por una señal fatal), el núcleo lo mueve a «terminado». Libera sus recursos (memoria, archivos, descriptores) y notifica al padre. El PCB queda como zombi hasta que el padre lo recoge.
Ninguna de estas transiciones la decide el programa. El programa solo hace cosas (llamar a read, terminar, etc.); el núcleo detecta esas acciones y cambia el estado en consecuencia. Por eso el estado es una propiedad del sistema operativo, no del programa.
5. Suspensión y swap
Los cinco estados anteriores asumen que el proceso está en memoria principal. Pero un sistema puede tener más procesos que memoria, y entonces el núcleo necesita suspender algunos: sacarlos de la memoria principal y guardarlos en disco (swap) para liberar espacio. Un proceso suspendido no puede ejecutarse, ni siquiera si está listo, porque no está en memoria.
La suspensión introduce dos estados nuevos:
| Estado | Que significa |
|---|---|
| Suspendido y listo | El proceso estaba listo para ejecutarse, pero se sacó de la memoria. Cuando se vuelva a cargar, estará listo de nuevo. |
| Suspendido y bloqueado | El proceso estaba bloqueado esperando un evento, y además se sacó de la memoria. Cuando se vuelva a cargar, seguirá bloqueado esperando el mismo evento. |
La suspensión la decide el núcleo (o el usuario, con señales como SIGSTOP), no el proceso. Es una herramienta para gestionar la memoria: cuando hay poca RAM, el núcleo suspende procesos que no se están usando activamente y los reanuda cuando hay espacio. Es el tema del curso de gestión de memoria.
En la práctica, en sistemas modernos con mucha RAM, la suspensión por swap es menos frecuente, pero el mecanismo sigue existiendo y se usa en contenedores, máquinas virtuales y sistemas embebidos.
6. El modelo de siete estados
Combinando los cinco estados clásicos con los dos suspendidos, se obtiene el modelo de siete estados, que es el que usan los sistemas operativos reales:
Las transiciones nuevas son:
- suspend (Listo → Suspendido y listo): el núcleo saca al proceso de la memoria.
- suspend (Bloqueado → Suspendido y bloqueado): el núcleo saca al proceso bloqueado de la memoria.
- activate (Suspendido y listo → Listo): el núcleo vuelve a cargar el proceso en memoria.
- activate (Suspendido y bloqueado → Bloqueado): el núcleo vuelve a cargar el proceso bloqueado.
- event occurs (Suspendido y bloqueado → Suspendido y listo): el evento que esperaba ocurre mientras está suspendido.
7. El proceso zombi
Cuando un proceso termina, no desaparece inmediatamente. El núcleo lo mueve a «terminado», libera su memoria, sus archivos y sus descriptores, pero conserva su PCB con el código de salida. Ese proceso se llama zombi: ya no se ejecuta ni ocupa recursos, pero sigue existiendo en la tabla de procesos hasta que su padre lo «recoge» con wait().
El zombi es un estado intermedio entre «terminado» y «liberado». Sirve para que el padre pueda consultar el código de salida del hijo. Si el padre nunca llama a wait(), el zombi se queda ahí indefinidamente, ocupando una entrada en la tabla de procesos. Si hay muchos zombis, se agota el límite de procesos y el sistema no puede crear procesos nuevos.
En ps, un zombi se reconoce por la letra Z en la columna STAT y por el nombre del proceso entre corchetes. En /proc/PID/status, el estado es Z (zombie).
$ ps -o pid,ppid,stat,comm -p 503
PID PPID STAT COMMAND
503 502 Z [worker]
$ grep state /proc/503/status
State: Z (zombie)
Si el padre termina antes que el hijo (o antes de recogerlo), el hijo queda huérfano y el núcleo le reasigna como padre al proceso 1 (o a un subreaper). El proceso 1, por diseño, recoge automáticamente a todos los huérfanos que terminan, así que un zombi huérfano no dura mucho. Es el tema 26.
Un zombi no ejecuta código ni ocupa memoria (más allá del PCB mínimo). Pero sí ocupa una entrada en la tabla de procesos, y si se acumulan, pueden agotar el límite de procesos del sistema. La solución es siempre recoger a los hijos con wait() o waitpid().
8. Los estados en linux (adelanto)
Linux no usa exactamente los cinco estados clásicos. En su lugar, usa un conjunto de estados que se muestra en la columna STAT de ps y en /proc/PID/status. El tema 7 los detalla con programas que provocan cada uno, pero aquí va un adelanto:
| Letra | Estado en linux | Corresponde a |
|---|---|---|
R | Running | En ejecución o listo para ejecutarse (Linux no distingue entre ambos en la salida de ps). |
S | Sleeping (interruptible) | Bloqueado esperando un evento, y puede despertarse por una señal. |
D | Uninterruptible sleep | Bloqueado en una operación de E/S de disco, no puede despertarse por señales. |
T | Stopped | Detenido por una señal (SIGSTOP, SIGTSTP) o por el depurador. |
Z | Zombie | Terminado, pero no recogido por el padre. |
t | Tracing stop | Detenido por el depurador (ptrace). |
X | Dead | El proceso está siendo destruido (estado transitorio, casi nunca se ve). |
La letra puede ir seguida de modificadores: + (en primer plano), s (líder de sesión), l (multihilo), < (alta prioridad), N (baja prioridad). Por ejemplo, Ss+ significa: dormido, líder de sesión, en primer plano.
9. Cómo el núcleo gestiona los estados
El núcleo gestiona los estados a través del planificador y de las colas. Cada estado corresponde a una cola o a una situación especial:
| Estado | Cola donde está | Quién lo saca de ahí |
|---|---|---|
| Nuevo | Ninguna (se está creando) | El núcleo, al terminar de crearlo. |
| Listo | Cola de listos | El planificador, al asignarle la CPU. |
| En ejecución | Ninguna (está en la CPU) | El núcleo, por timeout, bloqueo o terminación. |
| Bloqueado | Cola de espera del evento | El núcleo, cuando ocurre el evento. |
| Terminado / Zombi | Ninguna (espera al padre) | El padre, al llamar a wait(). |
El planificador es el componente del núcleo que decide que proceso de la cola de listos pasa a «en ejecución». Es el tema del curso siguiente (planificación de la CPU). Aquí nos basta con saber que existe y que es quien dispara la transición dispatch.
Cuando un proceso se bloquea, el núcleo no solo cambia su estado: también lo saca de la cola de listos y lo pone en la cola de espera correspondiente. Así, el planificador no lo considera candidato a ejecutarse hasta que se desbloquee. Cuando el evento ocurre, el núcleo lo saca de la cola de espera y lo pone en la cola de listos.
10. Un programa que provoca estados
El siguiente programa hace distintas cosas para provocar varios estados, y te permite observarlos con ps desde otra terminal:
#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
volatile sig_atomic_t continuar = 1;
void manejador(int sig)
{
continuar = 0;
}
int main(void)
{
printf("PID: %d\n", (int) getpid());
printf("Observa este proceso con: ps -o pid,stat,wchan,comm -p %d\n",
(int) getpid());
/* 1. Estado R: usar la CPU sin parar */
printf("\n[1] Usando la CPU durante 5 segundos (estado R)...\n");
unsigned long x = 0;
for (int i = 0; i < 5; i++) {
for (volatile int j = 0; j < 100000000; j++) x++;
sleep(1);
}
/* 2. Estado S: dormir (bloqueado interruptible) */
printf("\n[2] Durmiendo 10 segundos (estado S)...\n");
sleep(10);
/* 3. Estado T: detenerse por SIGSTOP */
printf("\n[3] Deteniéndose con SIGSTOP. Envía SIGCONT para continuar.\n");
fflush(stdout);
raise(SIGSTOP);
/* 4. Estado D: no se puede provocar fácilmente desde un programa */
printf("\n[4] Continuando tras SIGCONT.\n");
/* 5. Terminar */
printf("\n[5] Terminando (estado Z hasta que el padre recoge).\n");
return 0;
}
Al ejecutarlo, puedes observar desde otra terminal como cambia el estado:
$ gcc -std=c17 -Wall -Wextra -o estados estados.c
$ ./estados &
[1] 710
PID: 710
[1] Usando la CPU durante 5 segundos (estado R)...
$ ps -o pid,stat,wchan,comm -p 710
PID STAT WCHAN COMMAND
710 R+ - estados
$ sleep 6; ps -o pid,stat,wchan,comm -p 710
PID STAT WCHAN COMMAND
710 S+ hrtimer_nanosleep estados
$ sleep 12; ps -o pid,stat,wchan,comm -p 710
PID STAT WCHAN COMMAND
710 T+ - estados
$ kill -CONT 710
La columna WCHAN muestra en que función del núcleo está dormido el proceso. Cuando está en R, no está dormido (aparece -). Cuando está en S por sleep, aparece hrtimer_nanosleep. Es una pista útil para saber por que un proceso está bloqueado.
11. Resumen
- El estado de un proceso describe su situación frente al planificador: nuevo, listo, en ejecución, bloqueado o terminado.
- Los cinco estados clásicos se conectan por transiciones disparadas por eventos del núcleo: admit, dispatch, timeout, event wait, event occurs y release.
- La suspensión introduce dos estados más (suspendido y listo, suspendido y bloqueado) para gestionar la falta de memoria.
- El modelo de siete estados combina los cinco clásicos con los dos suspendidos.
- Un proceso zombi es uno que terminó pero cuyo PCB se conserva hasta que el padre lo recoge con
wait(). - Linux usa letras (R, S, D, T, Z, t, X) en lugar de los nombres clásicos, y no distingue entre «listo» y «en ejecución» en la salida de ps.
- El estado es un campo del PCB que el núcleo actualiza en cada transición.
12. Preguntas de repaso
Intenta responder cada una antes de abrir la respuesta.
1. ¿Cuáles son los cinco estados clásicos de un proceso?
Nuevo, listo, en ejecución, bloqueado y terminado. Son los estados que describen la vida de un proceso desde que se crea hasta que se libera.
2. ¿Que transición lleva a un proceso de «listo» a «en ejecución»?
La transición dispatch, que dispara el planificador al elegir un proceso de la cola de listos y asignarle la CPU.
3. ¿Que diferencia hay entre «listo» y «en ejecución»?
«Listo» significa que el proceso puede ejecutarse pero está esperando turno en la cola de listos. «En ejecución» significa que está usando la CPU en este momento. En un sistema con un solo núcleo, solo un proceso puede estar en ejecución a la vez.
4. ¿Que es un proceso zombi?
Es un proceso que terminó su ejecución pero cuyo PCB se conserva (con el código de salida) hasta que su padre lo recoge con wait(). No consume CPU ni memoria, pero ocupa una entrada en la tabla de procesos.
5. ¿Que es la suspensión y para que sirve?
Es sacar un proceso de la memoria principal y guardarlo en disco (swap) para liberar espacio. Introduce los estados «suspendido y listo» y «suspendido y bloqueado». La decide el núcleo, no el proceso.
6. ¿Que letra muestra ps para un proceso bloqueado en una operación de disco?
La letra D (uninterruptible sleep). Es un estado bloqueado en E/S de disco que no puede interrumpirse por señales, a diferencia de S (sleeping interruptible).
7. ¿Que significa la transición timeout?
Es cuando expira el cuanto de tiempo asignado a un proceso en ejecución. El núcleo lo interrumpe, lo mueve de «en ejecución» a «listo» y lo pone de nuevo en la cola de listos. Es involuntaria.
8. ¿Por que linux no distingue entre «listo» y «en ejecución» en ps?
Porque ambos estados se representan con la letra R (running). La distinción existe internamente en el núcleo, pero para el usuario no es relevante: un proceso en R está activo, ya sea ejecutándose o esperando turno inmediato.
9. ¿Que es la columna WCHAN en ps?
Muestra en que función del núcleo está dormido el proceso (si está bloqueado). Si el proceso está en R, aparece -. Es útil para saber por que un proceso está bloqueado.
10. ¿Que ocurre si un proceso termina y su padre no llama a wait?
El proceso queda como zombi indefinidamente, ocupando una entrada en la tabla de procesos. Si se acumulan muchos zombis, se puede agotar el límite de procesos del sistema.
Para practicar
- Compila y ejecuta
estados.c, y desde otra terminal observa como cambia el estado conps -o pid,stat,wchan,comm. - Crea un proceso zombi: escribe un programa que haga
fork(), que el hijo termine inmediatamente y que el padre no llame await(). Observa el zombi conpsy/proc/PID/status. - Lanza un proceso en segundo plano y deténlo con
kill -STOP PID. Observa el estadoT. Reanúdalo conkill -CONT PID. - Observa los estados de los procesos de tu sistema con
ps -e -o stat,comm | sort | uniq -cpara contar cuántos hay en cada estado. - Ejecuta un comando que haga E/S de disco intensiva (como
dd) y observa si aparece en estadoD. - Compara la salida de
ps -e -o statcon los estados del modelo de siete estados y anota que letras corresponden a cada uno.