Modelos de hilos - Procesos e Hilos
Volver a Procesos e Hilos Bloque 7 - Hilos y la biblioteca pthreads - Tema 29 de 43

Tema 29

Modelos de hilos

Los hilos se pueden implementar de distintas formás, dependiendo de quién los gestiona: el núcleo o una biblioteca de usuario. En este tema veras los modelos de hilos de usuario y de núcleo, los tres modelos de mapeo (1:1, N:1, M:N), y como linux implementa los hilos con clone y NPTL.

1. Qué son los modelos de hilos

Los modelos de hilos describen como se relacionan los hilos que ve el programador (hilos de usuario) con los hilos que el núcleo gestiona (hilos de núcleo). La pregunta fundamental es: ¿Quién programa los hilos? ¿La biblioteca de usuario o el núcleo?

La respuesta determina el rendimiento, el paralelismo y la complejidad del sistema. Hay tres modelos principales: 1:1, N:1 y M:N. Cada uno tiene ventajas y desventajas.

En el tema anterior viste que linux usa el modelo 1:1. En este tema veremos por que, y que alternativas existen.

2. Hilos de usuario

Los hilos de usuario (user-level threads) son gestionados por una biblioteca en espacio de usuario. El núcleo no sabe que existen: para el núcleo, el proceso tiene un sólo hilo (el que el núcleo programa).

La biblioteca de usuario se encarga de:

Ventajas:

Desventajas:

Hilos de usuario: Rápidos pero sin paralelismo

Los hilos de usuario son rápidos de crear y cambiar, pero no pueden ejecutarse en paralelo en multiples núcleos. Y Sí un hilo se bloquea en una syscall, todos los hilos se bloquean. Esto los hace inadecuados para la mayoria de las aplicaciones modernas.

3. Hilos de núcleo

Los hilos de núcleo (kernel-level threads) son gestionados directamente por el núcleo. El núcleo programa cada hilo independientemente, Como sí fuera un proceso ligero.

Ventajas:

Desventajas:

Linux, Windows y macOS usan hilos de núcleo. Es el modelo dominante en los sistemás modernos.

4. El modelo 1:1

En el modelo 1:1, cada hilo de usuario corresponde a un hilo de núcleo. Es el modelo más simple y el más usado.

Caracteristicas:

Usado por: Linux (pthreads/NPTL), Windows, macOS, Solaris.

Modelo 1:1: cada hilo de usuario corresponde a un hilo de núcleo. Nucleo: 3 hilos de núcleo (LWP) Hilo de usuario 1 Hilo de usuario 2 Hilo de usuario 3 Cada hilo de usuario = un hilo de núcleo Paralelismo real en multiples núcleos
Modelo 1:1: cada hilo de usuario corresponde a un hilo de núcleo. Es el modelo de linux, Windows y macOS.

5. El modelo N:1

En el modelo N:1, multiples hilos de usuario se mapean a un sólo hilo de núcleo. La biblioteca de usuario programa los hilos entre sí, y el núcleo sólo ve un hilo.

Caracteristicas:

Usado por: Solaris (green threads, antiguo), Java (green threads, antiguo), Sistemás embebidos sin soporte de hilos en el núcleo.

El modelo N:1 es raro hoy en dia porque la falta de paralelismo y el bloqueo total son limitaciones graves.

6. El modelo M:N

En el modelo M:N, M hilos de usuario se mapean a N hilos de núcleo (con M >= N). La biblioteca de usuario programa los hilos de usuario sobre los hilos de núcleo, Que el núcleo programa sobre la CPU.

Caracteristicas:

Usado por: Solaris (antiguo, con libthread), algunos sistemás de tiempo real.

El modelo M:N es el más flexible pero el más complejo. En la práctica, el overhead de la complejidad supera los beneficios, y la mayoria de los sistemás modernos usan 1:1.

Modelo M:N: 4 hilos de usuario se mapean a 2 hilos de núcleo. Nucleo: 2 hilos de núcleo (LWP) Hilo usuario 1 Hilo usuario 2 Hilo usuario 3 Hilo usuario 4 Hilo núcleo 1 Hilo núcleo 2 La biblioteca mapea M hilos de usuario a N hilos de núcleo
Modelo M:N: 4 hilos de usuario se mapean a 2 hilos de núcleo. La biblioteca programa los hilos de usuario sobre los de núcleo.

7. Comparacion de modelos

Caracteristica1:1N:1M:N
Paralelismo realSiNoSi (Sí N > 1)
Bloqueo en syscallSolo el hilo bloqueadoTodos los hilosSolo los hilos mapeados al hilo de núcleo bloqueado
Creacion de hiloLenta (syscall)Rapida (espacio de usuario)Rapida (espacio de usuario)
Cambio de contextoLento (Núcleo)Rapido (usuario)Mixto
complejidadBajaMediaAlta
Usado porLinux, Windows, macOSSolaris (antiguo), Java (antiguo)Solaris (antiguo)

El modelo 1:1 es el dominante porque ofrece paralelismo real y simplicidad, a costa de un poco más de overhead en la creacion. Los modelos N:1 y M:N son raros hoy en dia.

8. Cómo implementa linux los hilos

Linux implementa los hilos 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.

Cuando se crea un hilo pthread, la biblioteca llama a clone con los flags CLONE_VM, CLONE_FS, CLONE_FILES, CLONE_SIGHAND, CLONE_THREAD, CLONE_PARENT, etc. Esto hace que el hilo comparta la memoria, el sistema de archivos, los descriptores, los manejadores de senales, y el grupo de hilos con el proceso padre.

El resultado es que cada hilo pthread es un task_struct separado, con su propio TID, su propia pila, y sus propios registros. Pero comparte la memoria, los archivos, etc. con los demás hilos del proceso.

En linux, no hay una diferencia fundamental entre un proceso y un hilo. Ambos son task_struct. La diferencia esta en los flags de clone:

Esto es una de las decisiones de diseno más elegantes de linux: un sólo mecanismo (clone) para crear tanto procesos como hilos, y la diferencia esta en que se comparte.

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. Esto simplifica el núcleo y hace que los hilos sean tan eficientes como los procesos.

9. NPTL: la biblioteca de hilos de linux

NPTL (Native POSIX Thread library) es la implementación de pthreads en linux. Es la biblioteca que se usa cuándo se compila con -pthread. NPTL se basa en clone() y usa el modelo 1:1.

NPTL proporciona:

NPTL es la implementación estandar de pthreads en linux moderno. Reemplazo a linuxthreads en 2003, Cuándo se integro en el núcleo 2.6.

NPTL usa futex (fast userspace mutex) para la sincronizacion: los mutex se implementan en espacio de usuario, y sólo se hace una syscall (futex) Cuándo hay contención (el mutex esta bloqueado por otro hilo). Esto hace que los mutex sean muy rápidos cuándo no hay contención.

10. historia de los hilos en linux

La historia de los hilos en linux tiene varias etapas:

  1. Linuxthreads (1996): la primera implementación de pthreads en linux. Usaba clone() pero con un modelo que no era completamente POSIX-compliant. Cada hilo tenia su propio PID (no compartia el TGID), lo que causaba problemás con senales y con herramientas como ps.
  2. NPTL (2003): la implementación moderna. Usa el modelo 1:1 con CLONE_THREAD, por lo que todos los hilos comparten el mismo TGID (PID). Es completamente POSIX-compliant. Se integro en el núcleo 2.6.
  3. Estado actual: NPTL es la implementación estandar. Todos los sistemás linux modernos usan NPTL. Linuxthreads esta obsoleto.

La transicion de linuxthreads a NPTL fue importante porque resolvio muchos problemás de compatibilidad con POSIX y mejoro el rendimiento de los hilos.

NPTL es el estandar

En cualquier sistema linux moderno, la biblioteca de hilos es NPTL. Se puede verificar con getconf GNU_LIBPTHREAD_VERSION o ldd --Version. Si dice "NPTL", estas usando la implementación moderna.

11. Hilos en otros sistemas

Los hilos se implementan de forma distinta en otros sistemas:

SistemaImplementacionModeloCaracteristicas
LinuxNPTL (pthread)1:1Basado en clone(). Completamente POSIX-compliant.
WindowsCreatethread (Win32)1:1Hilos son ciudadanos de primera clase. TEB (Thread environment block).
macOSpthread (basado en mach)1:1Basado en el mach kernel. Cada hilo es un mach thread.
FreeBSDlibthr (pthread)1:1Basado en el modelo 1:1 desde freeBSD 7.
SolarislibthreadM:N (historico), 1:1 (moderno)Fue el pionero del modelo M:N. Ahora usa 1:1.

La tendencia general es hacia el modelo 1:1, porque ofrece paralelismo real y simplicidad. Los modelos N:1 y M:N se consideran obsoletos.

12. Un programa que demuestra modelos

El siguiente programa muestra como se pueden crear hilos con diferentes atributos y observar su comportamiento:

modelos_hilos.c

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

void *trabajo(void *arg)
{
    int id = *(int *) arg;
    printf("Hilo %d: PID=%d TID=%ld (gettid)\n",
           id, (int) getpid(), (long) syscall(SYS_gettid));
    sleep(1);
    return NULL;
}

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

    printf("Proceso principal: PID=%d TID=%ld\n",
           (int) getpid(), (long) syscall(SYS_gettid));

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

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

    printf("Todos los hilos terminaron\n");
    return 0;
}
terminal - ejecutar modelos_hilos

$ gcc -std=c17 -Wall -Wextra -pthread -o modelos_hilos modelos_hilos.c
$ ./modelos_hilos
Proceso principal: PID=1100 TID=1100
Hilo 1: PID=1100 TID=1101
Hilo 2: PID=1100 TID=1102
Hilo 3: PID=1100 TID=1103
Hilo 4: PID=1100 TID=1104
Todos los hilos terminaron

El programa demuestra el modelo 1:1: todos los hilos tienen el mismo PID (1100) pero TIDs distintos (1101-1104). Cada hilo es un task_struct separado en el núcleo, pero comparten el mismo TGID (PID).

13. Resumen

14. Preguntas de repaso

Intenta responder cada una antes de abrir la respuesta.

1. Qué son los hilos de usuario?

Hilos gestionados por una biblioteca en espacio de usuario. El núcleo no sabe que existen. Rapidos de crear pero sin paralelismo real.

2. Qué son los hilos de núcleo?

Hilos gestionados directamente por el núcleo. El núcleo programa cada hilo independientemente. Paralelismo real pero más lentos.

3. Qué es el modelo 1:1?

Cada hilo de usuario corresponde a un hilo de núcleo. Es el modelo de linux, Windows y macOS.

4. Qué es el modelo N:1?

Multiples hilos de usuario se mapean a un sólo hilo de núcleo. Sin paralelismo real. Usado por sistemás antiguos.

5. Qué es el modelo M:N?

M hilos de usuario se mapean a N hilos de núcleo. flexible pero complejo. Usado por solaris (antiguo).

6. Cómo implementa linux los hilos?

Con clone() y los flags CLONE_VM, CLONE_FS, CLONE_FILES, CLONE_SIGHAND, CLONE_THREAD, etc. Cada hilo es un task_struct separado.

7. Qué es NPTL?

Native POSIX Thread library: la implementación de pthreads en linux moderno. Usa el modelo 1:1 con clone().

8. Qué es linuxthreads?

La primera implementación de pthreads en linux (1996). Cada hilo tenia su propio PID. Fue reemplazada por NPTL en 2003.

9. Por que linux no distingue procesos de hilos?

Porque ambos son task_struct. La diferencia esta en los flags de clone(): CLONE_VM compartido = hilo, no compartido = proceso.

10. Qué es futex?

Fast userspace mutex: los mutex se implementan en espacio de usuario, y sólo se hace una syscall (futex) Cuándo hay contención. Hace que los mutex sean muy rápidos.

Para prácticar

  1. Compila y ejecuta modelos_hilos.c. Observa que todos los hilos tienen el mismo PID pero TIDs distintos.
  2. Verifica la version de NPTL con getconf GNU_LIBPTHREAD_VERSION.
  3. Lee /proc/PID/task para ver los hilos de un proceso.
  4. Usa ps -L -p PID para ver los hilos de un proceso.
  5. Escribe un programa que cree un hilo y verifique que comparte la memoria con el padre.
  6. Investiga la diferencia entre linuxthreads y NPTL.