A continuación se intentará explicar el concepto de hilo mediante un ejemplo. Imaginemos un servidor de archivos que ocasionalmente debe bloquearse esperando acceder al disco. Si el servidor tuviera varios hilos de control, se podría ejecutar un segundo hilo de control mientras el primero está suspendido. Esto provocaría un mejor rendimiento y utilización de los recursos. Si se crean dos procesos servidores independientes, ambos deberían compartir el buffer de caché, para lo cual deberían tener un espacio de direcciones común, lo cual complica su diseño. Normalmente se necesita un nuevo mecanismo que generalmente no se encuentra en los sistemas operativos, aunque no existe razón para esto.
Supongamos tres procesos independientes, cada uno con su propio contador de programa, su propia pila, su propio conjunto de registros y su propio espacio de direcciones. Los procesos no tienen ninguna relación entre sí, excepto que pueden comunicarse mediante primitivas del sistema para comunicación entre procesos: semáforos, paso de mensaje, monitores, etc.
Supongamos otra máquina, con un sólo proceso, pero dicho proceso tiene varios hilos de control, que suelen llamarse procesos ligeros o simplemente hilos (threads). Los hilos son como miniprocesos, ya que cada hilo se ejecuta de forma estrictamente secuencial, tiene su propio contador de programa y su propia pila. Los hilos comparten la CPU al igual que lo hacen los procesos en un sistema de tiempo compartido. Sólo en un sistema multiprocesador se pueden ejecutar realmente en paralelo. Los hilos pueden crear, igualmente, hilos hijos, y se pueden bloquear esperando la finalización de una llamada al sistema. Mientras un hilo se encuentra bloqueado, se puede ejecutar otro hilo del mismo proceso, exactamente igual que ocurre cuando un proceso se bloquea y se ejecuta otro proceso en la misma máquina. La analogía "hilo es a proceso, como proceso es a máquina" es válida en muchos sentidos.
Sin embargo los hilos de un mismo proceso no son
tan independientes como los procesos distintos. Todos los hilos
de un proceso comparten el mismo espacio de direcciones, con lo
cual comparten las mismas variables globales (las variables locales
no son compartidas, ya que se almacenan en la pila, y cada hilo
tiene su propia pila independiente). Como cada hilo tiene acceso
a cualquier dirección virtual, un hilo puede leer, escribir
o limpiar la pila de otro hilo de su mismo proceso. No existe
protección entre los hilos, ya que es muy difícil
proporcionarla y no debe ser necesaria.
Normalmente los procesos, que pueden ser de distintos usuarios, pueden ser hostiles entre sí. En cambio en un sistema multihilo, un proceso pertenece a un único usuario, y puede haber creado varios hilos para que cooperen entre sí.
Los hilos, además de compartir el espacio
de direcciones, comparten el conjunto de ficheros abiertos, procesos
hijos, relojes, señales, etc. Así pues, los hilos
resultan útiles cuando se necesite cooperación activa
y cercana en la resolución de un mismo problema.
Elementos de un Hilo | Elementos de un Proceso |
contador de programa (PC) | espacio de direcciones |
pila | variables globales |
registros | descriptores de archivos |
hilos hijos | procesos hijos |
estado | señales |
semáforos | |
relojes | |
información contable |
Todos los hilos comparten el mismo espacio de direcciones, y así
comparten también las mismas variables globales. Mientras
que los procesos pueden ser de distintos usuarios y competir por
recursos entre si, los hilos de un mismo proceso de usuario cooperan
entre si, sin luchar entre sí.
Al igual que los procesos tradicionales, los hilos pueden estar en alguno de los siguientes estados :
Además, en algunas ocasiones (según el diseño)
un hilo puede ser independizado (no tiene relación de parentesco
con ningún otro) en conjunción con cualquiera de
los estados anteriores. Cuando un hilo independizado finaliza
o cuando un hilo finalizado es independizado, cualquier memoria
asociada con él es liberada y el hilo no puede volver a
ser referenciado.
Un proceso puede tener uno o más hilos. Los hilos son un mecanismo que permite mejorar el rendimiento de los sistemas operativos tratando de reducir la sobrecarga producida por el cambio de contexto entre procesos. Los hilos de un mismo proceso comparten los recursos (memoria, archivos, etc.), y son la unidad de planificación. Así, un proceso será un objeto estático que posee un conjunto de recursos para una serie de hilos, que son los objetos dinámicos planificables.
Los hilos siempre pertenecen a un proceso, y no tienen existencia propia independiente. Cada hilo tiene un flujo de control, una pila y un estado propio. Ya que todos los recursos, a excepción de la CPU, son gestionados por el proceso, la comunicación entre hilos de un proceso es mucho más rápida y eficiente al compartir el mismo espacio de direcciones. Cuando se produce un cambio de contexto entre hilos de distintos procesos, se produce un cambio de contexto completo.
La implementación de hilos en un sistema operativo convierte a éste en mucho más rápido, pero surgen nuevos problemas de cara al programador, ya que varios hilos de un mismo proceso pueden acceder a una misma variable compartida, lo cual puede ocasionar inconsistencia en su valor. Sin embargo, a veces, la utilización de los hilos simplifica incluso la tarea del programador, dependiendo del tipo de aplicación.
El modelo de programación de hilos permite ignorar los detalles de la arquitectura, como el número de procesadores, para concentrarse en el algoritmo adecuado que exprese la concurrencia. Es pues un modelo adecuado para la programación concurrente. La utilización de la concurrencia en un lenguaje de programación requiere una cierta disciplina de programación junto a la utilización de nuevas técnicas. Los componentes concurrentes de un programa pueden ejecutarse de forma paralela en un multiprocesador.
Los hilos en un entorno multihilo tienen las siguientes características que pueden hacerles deseables en muchas aplicaciones que requieren multitarea :