3.2. CONCEPTO DE HILO.

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.

Figura 3-1 Tres procesos cada uno con un hilo.

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.

Figura 3-2 Un proceso con tres hilos.

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
pilavariables globales
registrosdescriptores de archivos
hilos hijosprocesos hijos
estadoseñales
semáforos
relojes
información contable

Figura 3-3 Elementos de un Hilo y un Proceso

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 :

  1. En ejecución (Running): cuando el hilo posee la CPU y se encuentra activo.
  2. Bloqueado (Suspend): cuando el hilo se encuentra esperando algún evento o a la espera de que otro libere el bloqueo por el que se encuentra detenido.
  3. Listo o preparado (Ready): cuando el hilo está preparado para su ejecución, y se encuentra a la espera de ser elegido por el planificador.
  4. Terminado (Finished): cuando el hilo ha finalizado, pero todavía no ha sido recogido por el hilo padre, aunque no puede ser planificado nunca más.

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 :