1. Programa, proceso, servicio e hilo¶
Estos cuatro conceptos aparecen en todo el módulo. Merece la pena tenerlos muy claros desde el principio.
1.1 Programa y programa ejecutable¶
Un programa es un conjunto de instrucciones escritas para resolver una tarea. Mientras está guardado en el disco no hace nada: es como una receta escrita en un libro de cocina.
Para que el ordenador pueda ejecutarlo, el código fuente tiene que traducirse a un formato que entienda el sistema:
| Lenguaje | Proceso de traducción | Resultado |
|---|---|---|
| C, C++, Rust | El compilador traduce a código máquina del procesador. | Ejecutable nativo: .exe (Windows), ELF (Linux), Mach-O (macOS). |
| Java, Kotlin | javac traduce a bytecode, que ejecuta la máquina virtual (JVM). |
Ficheros .class o .jar. El mismo .class funciona en cualquier sistema con JVM. |
| Python, JavaScript | Un intérprete lee y ejecuta el código. | No hay ejecutable: se lanza el intérprete con el fichero fuente. |
¿Son todos los ejecutables iguales?
No. Un .exe de Windows no funciona en Linux, y un ejecutable compilado para un procesador Intel no funciona directamente en uno ARM. Por eso Java usa bytecode: lo que se adapta a cada sistema es la JVM, no nuestro programa.
1.2 Proceso¶
Un proceso es un programa en ejecución. Cuando haces doble clic en un programa o escribes java HolaMundo en la terminal, el sistema operativo:
- Carga el código del programa en la memoria RAM.
- Le reserva una zona de memoria propia y aislada.
- Le asigna un número identificador único, el PID (Process Identifier).
- Crea su ficha de control, el PCB.
- Lo pone en la cola de procesos que esperan usar la CPU.
Con el ejemplo de la cocina:
| Cocina | Ordenador |
|---|---|
| La receta escrita en el libro | El programa, guardado en disco |
| El cocinero | La CPU: cada núcleo sigue las instrucciones una a una |
| Los ingredientes | Los datos de entrada |
| Estar cocinando la receta | El proceso: el programa en marcha |
Un programa, varios procesos
Si abres tres ventanas del Bloc de notas, hay un programa (notepad.exe) y tres procesos, cada uno con su PID y su memoria. Si escribes en una ventana, las otras no se enteran: cada proceso tiene su propia memoria.
La memoria de un proceso¶
Cada proceso tiene su propio espacio de direcciones, dividido en zonas:
| Zona | Qué guarda | Ejemplo en Java |
|---|---|---|
| Código (text) | Las instrucciones del programa. Solo lectura. | El bytecode cargado de los .class. |
| Datos | Variables globales y estáticas. | Los atributos static. |
| Heap (montículo) | Memoria que se pide durante la ejecución. | Todo lo que se crea con new. |
| Pila (stack) | Llamadas a métodos en curso, parámetros y variables locales. | Cada llamada a un método añade un marco a la pila. |
El sistema operativo impide que un proceso lea o escriba en la memoria de otro. Si un programa falla, no corrompe a los demás. La contrapartida es que, para que dos procesos se comuniquen, hace falta un mecanismo del sistema operativo (apartado 6).
1.3 El PCB: la ficha de cada proceso¶
El sistema operativo guarda la información de cada proceso en una estructura llamada PCB (Process Control Block, bloque de control de proceso):
| Campo | Para qué sirve |
|---|---|
| PID y PPID | Quién es el proceso y quién lo creó. |
| Estado | Nuevo, listo, en ejecución, bloqueado o terminado (apartado 3). |
| Contador de programa | La dirección de la siguiente instrucción que hay que ejecutar. |
| Registros de la CPU | Los valores con los que estaba calculando. |
| Información de memoria | Dónde están su código, sus datos, su heap y su pila. |
| Ficheros y conexiones abiertos | Los recursos que está usando. |
| Usuario y permisos | Qué puede hacer y a qué puede acceder. |
| Prioridad y estadísticas | Datos que usa el planificador (apartado 4). |
Cuando el sistema operativo quita la CPU a un proceso para dársela a otro, guarda en su PCB por dónde iba. Cuando le vuelve a tocar, restaura esos datos y el proceso continúa exactamente donde lo dejó, como si nada hubiera pasado. Es como el pósit que deja el cocinero cuando aparta la sopa para atender otro plato: «iba por el paso 4, el fuego estaba al medio».
1.4 PID, PPID y jerarquía de procesos¶
Todo proceso es creado por otro, su padre. Cada proceso guarda el PID de su padre, el PPID (Parent PID). Así se forma un árbol de procesos:
systemd (PID 1)
├── sshd (PID 812)
└── gnome-shell (PID 1500)
└── bash (PID 2201)
└── java HolaMundo (PID 2345)
- En Linux, el primer proceso que arranca es
systemd(oinit), con PID 1. Todos los demás descienden de él. - En Windows, la mayoría de los programas que abres con doble clic son hijos de
explorer.exe. - Si en una terminal escribes
java HolaMundo, la terminal es el padre y el procesojavaes el hijo.
Ver los procesos del sistema¶
| Sistema | Herramienta gráfica | Terminal |
|---|---|---|
| Windows | Administrador de tareas → pestaña Detalles (muestra el PID) | tasklist, o en PowerShell Get-Process |
| Linux | Monitor del sistema | ps -ef (con PPID), top, htop, pstree |
| macOS | Monitor de Actividad | ps -ef, top |
Ver el PID desde Java¶
Desde Java 9, la clase ProcessHandle permite consultar el propio proceso y su padre:
public class MiPid {
public static void main(String[] args) {
ProcessHandle yo = ProcessHandle.current();
System.out.println("Mi PID: " + yo.pid());
yo.parent().ifPresent(padre ->
System.out.println("Mi PPID: " + padre.pid() + " (" + padre.info().command().orElse("?") + ")"));
}
}
Salida de ejemplo, ejecutado desde una terminal de Linux:
parent() devuelve un Optional porque el padre podría haber terminado ya.
1.5 Procesos zombis y huérfanos¶
Cuando un proceso hijo termina, devuelve un código de salida (0 si todo fue bien). El padre tiene la obligación de recoger ese código.
- Proceso zombi. El hijo ya ha terminado, pero el padre todavía no ha recogido su código de salida. El zombi no usa CPU ni memoria, pero sigue ocupando una entrada en la tabla de procesos y un PID. Si se acumulan miles, el sistema se queda sin PID libres. En
psaparece con el estadoZo la palabra<defunct>. - Proceso huérfano. El padre termina antes que el hijo. El hijo sigue funcionando y el sistema lo «adopta»: pasa a ser hijo del PID 1, que recogerá su código cuando termine. No es un error; muchos servicios se lanzan así a propósito.
En Java
El método waitFor() de la clase Process espera a que el hijo termine y recoge su código de salida. Es lo que evita que quede zombi (apartado 5).
No confundir
Un proceso que se queda bloqueado para siempre esperando un dato que nunca llega no es un zombi: sigue vivo. Es un error de programación. El zombi, en cambio, ya está muerto.
1.6 Servicios¶
Un servicio (en Linux, demonio o daemon) es un proceso que:
- Se ejecuta en segundo plano, sin ventana ni interacción con el usuario.
- Normalmente arranca con el sistema y sigue funcionando aunque nadie haya iniciado sesión.
- Atiende peticiones: imprimir, conexiones remotas, consultas a una base de datos, páginas web…
Ejemplos: el servicio de cola de impresión, sshd (conexiones SSH), un servidor web, MySQL o el servicio de actualizaciones.
| Sistema | Ver y gestionar servicios |
|---|---|
| Windows | services.msc, o en PowerShell Get-Service y Restart-Service Spooler |
| Linux | systemctl status ssh, systemctl restart ssh, systemctl list-units --type=service |
| macOS | launchctl list |
En los Temas 3 y 4 programarás tus propios servicios: programas que esperan conexiones de clientes por la red.
1.7 Hilos¶
Un hilo (thread) es un flujo de ejecución dentro de un proceso. Todo proceso tiene al menos uno, el hilo principal, que en Java es el que ejecuta el método main.
Un proceso puede tener varios hilos. Por ejemplo, un procesador de textos tiene un hilo que atiende el teclado, otro que revisa la ortografía y otro que guarda una copia automática.
| Proceso | Hilo | |
|---|---|---|
| Memoria | Propia y aislada | Compartida con los demás hilos del proceso (solo la pila es propia) |
| Coste de crearlo | Alto: el SO reserva memoria, crea el PCB… En Java, arrancar otra JVM tarda décimas de segundo. | Bajo: microsegundos |
| Comunicación | Necesita mecanismos del SO (tuberías, ficheros, sockets) | Directa, a través de variables compartidas |
| Si falla | No afecta a los demás procesos | Puede hacer caer todo el proceso |
| Quién lo ejecuta | La CPU ejecuta los hilos del proceso | Es la unidad que realmente ejecuta la CPU |
¿Procesos o hilos?
Se usan procesos cuando queremos aislamiento (que un fallo no tumbe al resto) o ejecutar otro programa. Se usan hilos cuando queremos hacer varias cosas dentro del mismo programa compartiendo datos de forma rápida. Los hilos se estudian a fondo en el Tema 2.
Preguntas de repaso¶
- ¿Qué diferencia hay entre un programa y un proceso? Pon un ejemplo con una aplicación que uses a diario.
- ¿Qué cuatro zonas tiene la memoria de un proceso? ¿En cuál se guarda un objeto creado con
new? - ¿Para qué sirve el contador de programa del PCB?
- Si cierras la terminal desde la que has lanzado un programa con
nohup, ¿qué tipo de proceso queda? ¿Quién pasa a ser su padre? - ¿Por qué un servicio no tiene ventana? ¿Cómo lo reiniciarías en tu sistema operativo?
- Indica dos ventajas de los hilos frente a los procesos y una ventaja de los procesos frente a los hilos.