- Consideraciones de programación.
Algunos autores, como John Ousterhout [OUS94], consideran
que los hilos sólo deben emplearse cuando se desea y es
posible una concurrencia verdadera, y no en entornos uniprocesador.
Consideran que son demasiado complicados de usar para la mayoría
de los programadores, incluso para los expertos, y plantean la
programación con eventos como alternativa para la
mayoría de los casos. Las problemas se deben a las siguientes
causas :
- Complejidad :
Aunque es cierto que la programación con hilos puede proporcionar
una forma más natural de resolver los problemas, existen
otras cosas que se deben tener en cuenta. La programación
con hilos es más difícil que la clásica programación
secuencial. Por ejemplo, cuando se mantiene, depura u optimiza
una aplicación con hilos, se deben tener en cuenta la existencia
de múltiples hilos de código en ejecución.
Por ello generalmente es más fácil depurar y optimizar
un programa de hilo simple.
- Sincronización :
Se debe coordinar el acceso a los datos compartidos mediante bloqueos.
Olvidar un bloqueo puede producir la corrupción de los
datos.
- Posibilidad de deadlock :
Las dependencias circulares en los bloqueos pueden originar deadlock.
- Depuración difícil,
debido a las dependencias entre los datos y las dependencias de
tiempo. Depurar en un sistema multiprocesador es más complicado,
más costoso, y los errores no siempre son reproducibles.
Una biblioteca de hilos puede ser útil para detectar y
analizar errores en un entorno uniprocesador antes de ser probada
en un sistema multiprocesador. Existen dos tipos de errores, los
errores serie que pueden ocurrir en un entorno uniprocesador,
y los errores paralelos que son inherentes a una ejecución
paralela, y son difíciles de detectar.
- Rompen la abstracción,
lo que impide diseñar módulos independientes.
- Obtener un buen rendimiento es difícil.
Los bloqueos demasiado simples (grano grueso) disminuyen el nivel
de concurrencia, mientras que los bloqueos de grano fino son demasiado
complicados. Además la velocidad de cambio de contexto
del sistema operativo influye notablemente en el rendimiento.
- Soporte escaso :
El código es difícil de transportar a otras arquitecturas
que no soportan hilos. Las librerías estándar no
suelen ser hilo-seguras. Las llamadas al kernel o al sistema de
gestión de ventanas pueden no estar preparadas para soportar
múltiples hilos.
- Disponibilidad de herramientas :
Para favorecer el desarrollo de aplicaciones multihilo, la industria
necesitará crear herramientas de depuración y optimización
más refinadas. Sin embargo, la tecnología de los
depuradores y optimizadores es relativamente joven lo que a corto
plazo supone un problema para los programadores. Un entorno de
programación multihilo debe proporcionar depuradores con
soporte multihilo [CAS90]. La información debe ser extraída
del TCB (bloque de control del hilo) y hacerla disponible al usuario.
Los cambios de contexto deberían ser visibles para el usuario.
Por ejemplo, cuando se va a producir un cambio de contexto, el
usuario podría elegir si continua depurando después
del punto de suspensión o si cambia al contexto de otro
hilo. Además se podrían presentar ventanas de depuración
separadas para cada hilo dentro de un proceso.
- Utilización de código no seguro :
Se debe tener mucho cuidado a la hora de mezclar código
multihilo con código no hilo-seguro, es decir, código
no preparado para ejecución en un entorno multihilo.
Obviamente, la utilización de los hilos no
es sencilla de cara al programador. Un entorno multihilo brinda
ventajas, pero puede también incrementar la complejidad
de la programación. Algunos problemas típicos encontrados
por los programadores cuando trabajan con hilos son :
- Condiciones de ejecución o race conditions
: Pueden ocurrir cuando dos o más
hilos están accediendo al mismo recurso sin que la aplicación
pueda determinar en qué orden los hilos accedieron al recurso.
Un ejemplo sería una variable global que tiene que ser
accedida y modificada por los hilos de una forma ordenada. El
resultado puede depender del orden en el que esta variable sea
modificada. Para evitar las condiciones de ejecución, pueden
usarse facilidades de sincronización de hilos, tales como
variables de condición y mútex, para imponer una
secuencia entre los hilos.
- Bloqueo mutuo o deadlock :
Puede ocurrir cuando dos o más hilos están bloqueados
esperando a que se encuentren disponibles recursos que poseen
los mismos hilos. Un ejemplo sería un hilo A que bloquea
un mútex c esperando a que
un hilo B libere el mútex d.
Al mismo tiempo, el hilo B desea bloquear el mútex d
y espera a que A libere el mútex c.
Para evitar el bloqueo mutuo, la técnica usual es emplear
una aproximación "todo o nada". Si un hilo no
es capaz de adquirir exclusivamente todos los recursos que necesita,
debe liberar todos los recursos que logró adquirir hasta
el momento.
- Bloqueos conflictivos :
Pueden provocar un pobre rendimiento debido a que un hilo bloquee
un mútex más tiempo del necesario o de lo tolerable,
haciendo esperar al resto de hilos. Los mútex deben ser
liberados en el momento que ya no sean necesarios para permitir
el máximo nivel de concurrencia entre los hilos. Se debe
tener precaución de evitar mútex bloqueados durante
largas operaciones, como es el caso de E/S. Una forma de evitar
la reducción del rendimiento, debido a un bloqueo conflictivo,
es identificar los recursos compartidos que pueden dividirse de
forma que un hilo no asesine a los otros, mientras accede a recursos
que son realmente privados.
- Código no hilo-seguro :
Código no hilo-seguro es código que no trabaja adecuadamente
en un entorno multihilo. Para usar código no hilo-seguro
en un entorno multihilo se debe emplear un bloqueo global. El
bloqueo global usa un mútex global. Este bloqueo puede
ser usado en la parte de código que llama a las rutinas
o en las rutinas. El uso de un bloqueo global garantiza que el
mismo mútex sea usado por cualquier rutina que trabaje
con código no hilo-seguro. Una alternativa más compleja
para trabajar con código no hilo-seguro sería, cuando
sea posible, recodificar el código para que sea hilo-reentrante.