Que es un hilo - Procesos e Hilos
Volver a Procesos e Hilos Bloque 7 - Hilos y la biblioteca pthreads - Tema 28 de 43

Tema 28

Que es un hilo

Hasta ahora hemos visto procesos: programás en ejecución con su propia memoria, su propio estado y su propio PID. Pero un proceso puede tener dentro de sí varias lineas de ejecución que comparten la misma memoria. Esas lineas son los hilos. En este tema veras que es un hilo, Que comparten y que tienen propio, y por que son una herramienta poderosa para la concurrencia.

1. Qué es un hilo

Un hilo (thread) es una linea de ejecución dentro de un proceso. Un proceso puede tener uno o más hilos, Que comparten el mismo espacio de direcciónes (Código, datos, heap) pero cada uno tiene su propia pila y su propio estado de la CPU (registros, contador de programa).

Los hilos son la forma de dividir un proceso en multiples táreas que se ejecutan concurrentemente. A diferencia de los procesos (Que se crean con fork y tienen memoria propia), los hilos comparten memoria y se crean con pthread_create (o clone en linux).

La analogia clasica es la de un restaurante: el proceso es el restaurante (con su cocina, ingredientes y recetas), y los hilos son los cocineros que trabajan en la misma cocina. Todos comparten los mismos ingredientes (Memoria) y las mismás recetas (Código), pero cada uno tiene su propia estacion de trabajo (pila) y su propia tárea (contador de programa).

Hilo = linea de ejecución

Un hilo es simplemente una secuencia de instrucciones que se ejecuta. Un proceso con un sólo hilo es como los programás que hemos visto hasta ahora: una sola linea de ejecución. Un proceso con varios hilos tiene varias lineas de ejecución que avanzan concurrentemente.

2. Proceso vs hilo

La diferencia fundamental entre un proceso y un hilo es la Memoria:

CaracteristicaProcesoHilo
Espacio de direcciónesPropio (independiente)Compartido con otros hilos del mismo proceso
Memoria (Código, datos, heap)PropiaCompartida
PilaPropiaPropia (cada hilo tiene la suya)
Registros y PCPropiosPropios (cada hilo tiene los suyos)
PIDUnicoCompartido (todos los hilos del proceso tienen el mismo PID)
TIDN/AUnico por hilo
Creacionfork() (costosa)pthread_create() (barata)
Cambio de contextocostoso (cambia tablas de páginas)Barato (no cambia tablas de páginas)
ComunicacionIPC (pipes, sockets, etc.)Memoria compartida (directa)
AislamientoAlto (un proceso no afecta a otros)Bajo (un hilo puede corromper la memoria de todos)

Los hilos son más ligeros que los procesos: se crean más rápido, se cambian más rápido, y se comunican más fácilmente (porque comparten memoria). Pero ofrecen menos aislamiento: un error en un hilo puede corromper la memoria de todos los hilos del proceso.

3. Lo que comparten los hilos

Todos los hilos de un proceso comparten:

Esta comparticion es lo que hace a los hilos poderosos: pueden comunicarse simplemente leyendo y escribiendo variables compartidas, Sin necesidad de IPC (pipes, sockets, etc.).

4. Lo que cada hilo tiene propio

Cada hilo tiene su propio:

La pila es el recurso más importante que cada hilo tiene propio. Sin pilas separadas, los hilos no podrian ejecutar funciónes de forma independiente.

Un proceso con tres hilos. Todos comparten el código, los datos y el heap. Cada hilo tiene su propia pila y sus propios registros. Proceso (PID 1000) - un espacio de direcciónes Codigo (texto) - compartido main(), Función1(), Función2() - todos los hilos ejecutan el mismo código Datos y BSS - compartidos variables globales - todos los hilos las ven y modifican Heap (monticulo) - compartido malloc/free - todos los hilos comparten la memoria dinaminima Pila del hilo 1 variables locales llamadas a funciónes registros, PC TID=1001 Pila del hilo 2 variables locales llamadas a funciónes registros, PC TID=1002 Pila del hilo 3 variables locales llamadas a funciónes registros, PC TID=1003
Un proceso con tres hilos. Todos comparten código, datos y heap. Cada hilo tiene su propia pila, registros y TID.

5. El modelo de hilos

Los hilos se pueden implementar de dos formas:

Linux usa hilos de núcleo: cada hilo es un proceso ligero (LWP, lightweight process) gestionado por el núcleo. Esto significa que el núcleo programa los hilos directamente, y pueden ejecutarse en paralelo en multiples núcleos.

Los modelos de mapeo entre hilos de usuario y de núcleo son:

ModeloDescripcionUsado por
1:1Cada hilo de usuario corresponde a un hilo de núcleo.Linux (pthreads), Windows, macOS.
N:1Multiples hilos de usuario mapean a un sólo hilo de núcleo.Sistemás antiguos (Solaris green threads).
M:NMultiples hilos de usuario mapean a un número menor de hilos de núcleo.Solaris (antiguo), algunos sistemás de tiempo real.

Linux usa el modelo 1:1: cada hilo de usuario (pthread) corresponde a un hilo de núcleo (LWP). Esto permite que los hilos se ejecuten en paralelo en multiples núcleos y que el núcleo programe cada hilo independientemente.

El tema 29 profundiza en los modelos de hilos y en como linux los implementa con clone.

6. Hilos en el espacio de direcciónes

Todos los hilos de un proceso comparten el mismo espacio de direcciónes. Esto significa que la misma dirección virtual apunta a la misma página fica para todos los hilos. No hay traducción diferente por hilo.

Las pilas de los hilos se colocan en regiones distintas del espacio de direcciónes, tipicamente en la region mapeada (entre el heap y la pila principal). Cada hilo tiene su propia region de pila, de tamano fijo (por omision, 8 MB en linux).

En /proc/PID/maps, se pueden ver las pilas de los hilos:

terminal - pilas de hilos en /proc

$ grep stack /proc/PID/maps
7f8a3c000000-7f8a3c021000 rw-p ... [stack:1001]
7f8a3b800000-7f8a3b821000 rw-p ... [stack:1002]
7ffffffde000-7ffffffff000 rw-p ... [stack]

La etiqueta [stack:1001] Indica la pila del hilo con TID 1001. La etiqueta [stack] (Sin número) es la pila del hilo principal (el proceso).

7. El TCB: Thread control block

ASí como un proceso tiene un PCB (Process control block), un hilo tiene un TCB (Thread control block). El TCB guarda la información específica del hilo:

En linux, el TCB no es una estructura separada: se integra en el task_struct del hilo. El task_struct tiene campos específicos para hilos (Como la pila, los registros, la máscara de senales) y campos compartidos con el proceso (Como la memoria, los archivos, etc.).

La biblioteca pthreads (NPTL en linux) mantiene su propia estructura de TCB en espacio de usuario, Que complementa al task_struct del núcleo. Esta estructura guarda información como el estado del hilo (detached, joined), los atributos, y los datos específicos del hilo.

8. Hilos en linux: clone

En linux, los hilos se crean con la syscall clone(), Que es una version generalizada de fork. clone permite especificar que recursos se comparten entre el proceso padre y el hijo:

Flag de cloneRecurso compartido
CLONE_VMEspacio de direcciónes (Memoria).
CLONE_FSInformacion del sistema de archivos (cwd, root, umask).
CLONE_FILESTabla de descriptores de archivo.
CLONE_SIGHANDManejadores de senales.
CLONE_THREADMismo grupo de hilos (mismo PID/TGID).
CLONE_PARENTMismo padre.
CLONE_VFORKEl padre se suspende hasta que el hijo llame a exec o _exit (Como vfork).

fork() es equivalente a clone() Sin flags (CLONE_SIGCHLD). Un hilo (pthread) se crea con clone() con todos los flags CLONE_* activados: comparte memoria, archivos, senales, etc., pero tiene su propia pila y su propio TID.

Por eso, en linux, la diferencia entre un proceso y un hilo es sólo que flags se pasan a clone(). Un "proceso" es un clone sin CLONE_VM (Memoria separada). Un "hilo" es un clone con CLONE_VM (Memoria compartida).

Linux no distingue procesos de hilos

En linux, no hay una diferencia fundamental entre procesos e hilos. Ambos son task_struct. La diferencia esta en los flags de clone: Sí se comparte la memoria (CLONE_VM), es un hilo; Sí no, es un proceso. Esto es una de las decisiones de diseno más elegantes de linux.

9. Hilos en otros sistemas

En windows, los hilos son ciudadanos de primera clase: el sistema operativo los gestiona directamente con la API Createthread. Cada hilo tiene su propio TEB (Thread environment block) y su propia pila. Los procesos y los hilos son entidades distintas.

En macOS y otros sistemás unix, los hilos se implementan con pthreads, Que en macOS se basa en el mach kernel. Cada hilo es un "Mach thread" gestionado por el núcleo.

La diferencia principal entre linux y windows es que linux usa clone() para crear tanto procesos como hilos (la diferencia esta en los flags), mientras que windows tiene APIs separadas (Createprocess y createthread).

10. Ventajas de los hilos

11. Desventajas de los hilos

Los hilos son una espada de doble filo

Los hilos son poderosos pero peligrosos. Compartir memoria fácilita la comunicacion, pero también fácilita la corrupcion de datos. Siempre se debe sincronizar el acceso a datos compartidos con mutex u otras herramientas de sincronizacion.

12. Un programa que demuestra hilos

El siguiente programa crea 3 hilos que comparten una variable global y la incrementan:

hilos_demo.c

#define _POSIX_C_SOURCE 200809L
#include 
#include 
#include 
#include 

/* Variable compartida por todos los hilos */
static int contador = 0;

void *trabajo(void *arg)
{
    int id = *(int *) arg;
    for (int i = 0; i < 5; i++) {
        contador++;  /* acceso concurrente (Sin sincronizacion) */
        printf("Hilo %d: contador = %d\n", id, contador);
        usleep(100000);
    }
    return NULL;
}

int main(void)
{
    pthread_t hilos[3];
    int ids[3] = {1, 2, 3};

    printf("PID: %d (todos los hilos comparten este PID)\n", (int) getpid());

    for (int i = 0; i < 3; i++)
        pthread_create(&hilos[i], NULL, trabajo, &ids[i]);

    for (int i = 0; i < 3; i++)
        pthread_join(hilos[i], NULL);

    printf("Contador final: %d (esperado: 15)\n", contador);
    return 0;
}
terminal - compilar y ejecutar hilos_demo

$ gcc -std=c17 -Wall -Wextra -pthread -o hilos_demo hilos_demo.c
$ ./hilos_demo
PID: 1090 (todos los hilos comparten este PID)
Hilo 1: contador = 1
Hilo 2: contador = 2
Hilo 3: contador = 3
Hilo 1: contador = 4
...
Contador final: 15 (esperado: 15)

Los 3 hilos comparten el mismo PID y la misma variable contador. Cada hilo incrementa el contador y muestra su valor. El contador final deberia ser 15 (3 hilos x 5 incrementos), pero puede ser menos sí hay una condicion de carrera (tema 34).

Observa el flag -pthread en la compilacion: es necesario para enlazar la biblioteca de hilos.

Tambien se puede verificar que los hilos comparten el mismo PID con ps:

terminal - ver hilos con ps

$ ./hilos_demo &
[1] 1090
$ ps -L -p 1090 -o pid,tid,comm
    PID     TID COMMAND
   1090    1090 hilos_demo
   1090    1091 hilos_demo
   1090    1092 hilos_demo
   1090    1093 hilos_demo

Los 4 hilos (1 principal + 3 creados) tienen el mismo PID (1090) pero TIDs distintos (1090-1093). Esto confirma que los hilos comparten el PID del proceso.

13. Resumen

14. Preguntas de repaso

Intenta responder cada una antes de abrir la respuesta.

1. Qué es un hilo?

Una linea de ejecución dentro de un proceso. Comparte el espacio de direcciónes con otros hilos del mismo proceso, pero tiene su propia pila y registros.

2. Qué comparten los hilos de un proceso?

Codigo, datos globales, heap, descriptores de archivo, cwd, entorno, manejadores de senales, y PID.

3. Qué tiene propio cada hilo?

Pila, registros de la CPU, contador de programa, TID, errno, Máscara de senales bloqueadas, y prioridad.

4. Por que los hilos son más rápidos que los procesos?

Porque se crean sin copiar la memoria (comparten el espacio de direcciónes), y el cambio de contexto no requiere cambiar las tablas de páginas.

5. Qué modelo de hilos usa linux?

El modelo 1:1: cada hilo de usuario (pthread) corresponde a un hilo de núcleo (LWP). Esto permite paralelismo real en multiples núcleos.

6. Cómo se crean hilos en linux?

Con la syscall clone() con los flags CLONE_VM, CLONE_FS, CLONE_FILES, CLONE_SIGHAND, CLONE_THREAD, etc. La biblioteca pthreads usa clone internamente.

7. Qué es un TCB?

Thread control block: la estructura que guarda la información de un hilo (TID, estado, registros, pila, Máscara de senales, errno).

8. Por que los hilos necesitan sincronizacion?

Porque comparten memoria. El acceso concurrente a datos compartidos puede causar condiciones de carrera (resultados incorrectos).

9. Cómo se compila un programa con pthreads?

Con el flag -pthread: gcc -std=c17 -Wall -Wextra -pthread programa.c -o programa.

10. Qué diferencia hay entre un hilo y un proceso en linux?

La diferencia esta en los flags de clone(): Sí se comparte la memoria (CLONE_VM), es un hilo; Sí no, es un proceso. Ambos son task_struct.

Para prácticar

  1. Compila y ejecuta hilos_demo.c. Observa que todos los hilos tienen el mismo PID.
  2. Mientras se ejecuta, observa los hilos con ps -L -p PID.
  3. Lee /proc/PID/maps y busca las pilas de los hilos ([stack:TID]).
  4. Ejecuta hilos_demo varias veces. ¿El contador final siempre es 15? ¿Por que?
  5. Escribe un programa que cree 10 hilos y muestre sus TIDs.
  6. Compara el tiempo de creacion de un proceso (fork) con el de un hilo (pthread_create).