Main logo La Página de DriverOp

Capítulo 1. ¿Qué son los hilos de ejecución? ¿Porqué usarlos?

En este capítulo:

  • Historia
  • Definiciones
  • Un ejemplo
  • Tiempo compartido
  • ¿Porqué usar hilos de ejecución?

Historia

En los primeros días de la computación, toda la programación era esencialmente tratada en un solo hilo. Los programas se creaban perforando tarjetas o cintas, con las que formabas tu grupo de tarjetas que enviabas luego al centro local de computación y, tras de un par de días, recibías otro grupo de tarjetas que, si estabas de suerte, contenían los resultados solicitados. Todo el procesamiento era por lotes, de ningún modo crítico, basado en la premisa de que el primero que llegaba era el primero en ser servido y cuando tu programa estaba corriendo, tenía uso exclusivo del tiempo de la computadora.

Las cosas han cambiado. El concepto de múltiples hilos de ejecución aparece por primera vez con los sistemas de tiempo compartido, donde más de una persona podía conectarse a una computadora central a la vez. Era importante asegurarse que el tiempo de procesamiento de la máquina era dividido adecuadamente entre todos los usuarios; los sistemas operativos de ese tiempo comienzan a usar los conceptos de “proceso” (process) e “hilos de ejecución” (threads). Las computadoras de escritorio han visto un progreso similar. Los primeros DOS y Windows funcionaban con un único hilo de ejecución. Los programas, o funcionaban en forma exclusiva en la máquina, o no funcionaban. Con la creciente sofisticación de las aplicaciones y la creciente demanda de computadoras personales, especialmente en lo relativo a la performance gráfica y el trabajo en red, los sistemas operativos multiproceso y multihilo se volvieron algo común. Las aplicaciones multihilo en las PC’s fueron principalmente conducidas por la búsqueda de una mejor performance y usabilidad.

Definiciones

El primer concepto a definir es el del proceso. La mayoría de los usuarios de Windows 95, 98 y NT intuyen bastante bien lo que es un proceso. Lo ven como un programa que corre en la computadora, co-existiendo y compartiendo el microprocesador, la memoria y otros recursos con otros programas. Los programadores saben que un proceso es invocado por un código ejecutable, como también saben que ese código tiene una única existencia y que las instrucciones ejecutadas por ese proceso son procesadas de una manera ordenada. En suma, los procesos se ejecutan en forma aislada. Los recursos que usan (memoria, disco, E/S, tiempo del microprocesador) son virtualizados, de modo que todos los procesos tienen su propio grupo de recursos virtuales que son exclusivos de ese proceso. El sistema operativo provee esta virtualización. Los procesos ejecutan módulos de código. Estos pueden ser independientes, en el sentido de que, los módulos ejecutables de código que competen al Windows Explorer son independientes de los del Microsoft Word. Sin embargo, éstos también pueden ser compartidos, como es el caso de las DLL’s. El código de una DLL típicamente es ejecutado en el contexto de muchos procesos diferentes, y habitualmente en forma simultánea. La ejecución de instrucciones no es totalmente ordenada por los procesos: Microsoft Word no deja de abrir un documento sencillamente porque la cola de impresión está enviando algo a la impresora! Por supuesto, cuando diferentes procesos interactúan entre sí, el programador debe establecer un orden, un problema central que será tratado luego.

Nuestro próximo concepto es el del hilo de ejecución (Thread). Los hilos de ejecución fueron desarrollados cuando se vio claramente el deseo de tener aplicaciones que realizaran varias acciones con mayor libertad en cuanto al orden, posiblemente, realizando varias acciones en el mismo momento. En situaciones donde algunas acciones pudieran causar una demora considerable a un hilo de ejecución (por ejemplo, cuando se espera que el usuario haga algo), era más deseable que el programa siguiera funcionando, ejecutando otras acciones concurrentemente (por ejemplo, verificación ortográfica en segundo plano, o procesamiento de los mensajes que arriban desde la red). Sin embargo, crear todo un nuevo proceso para cada acción concurrente y luego hacer que ese proceso se comunicara con el primero era generalmente una sobrecarga demasiado grande.

Un ejemplo

Si se necesita ver un buen ejemplo de programación multihilo, entonces el Windows Explorer (aka Windows Shell) es un ejemplo excelente. Haz doble clic en “Mi PC” y abre varias subcarpetas abriendo nuevas ventanas a medida que lo haces. Ahora, realiza una larga operación de copia en una de esas ventanas. La barra de progreso aparece y esa ventana en particular deja de responder al usuario. Sin embargo, todas las demás ventanas son perfectamente usables. Obviamente, varias cosas se están haciendo en el mismo momento, pero sólo una copia de explorer.exe está corriendo. Esa es la esencia de la programación multihilo.

Tiempo compartido.

En la mayoría de los sistemas que soportan varios hilos de ejecución, puede haber muchos usuarios haciendo llamadas simultáneas al sistema. Para responder a todas estas demandas, se suele necesitar una cantidad de hilos de ejecución que suele ser superior al número de procesadores que existen físicamente en el sistema. Esto es posible gracias a que la mayoría de los sistemas permiten compartir el tiempo del procesador, y así solucionar este problema. En un sistema con tiempo compartido, los hilos de ejecución corren por un corto espacio y luego son invalidados; es decir, un temporizador en el hardware de la máquina se dispara, lo que causa que el sistema operativo re-evalúe qué hilos de ejecución deben correr, pudiendo detener la ejecución de los hilos en funcionamiento y continuando la ejecución de otros hilos que habían quedado detenidos. Esto permite que las máquinas, aún con un solo procesador, puedan correr muchos hilos de ejecución. En las PC’s, los tiempos compartidos tienden a ser de alrededor de 55 milisegundos.

¿Porqué usar hilos de ejecución?

Los hilos de ejecución no deben alterar la semántica de un programa. Ellos cambian simplemente los tiempos de operación. Como resultado, son casi siempre usados como una solución elegante a problemas de performance. Aquí hay algunos ejemplos de situaciones donde puedes usar hilos de ejecución:

  • Realizar largos procesamientos: Cuando una aplicación de Windows está realizando cálculos, no puede procesar ningún mensaje. Como resultado, la pantalla no puede ser actualizada.
  • Realizar procesamientos en segundo plano: Algunas tareas pueden no ser críticas, pero necesitan ser ejecutadas continuamente.
  • Realizar tareas de E/S: E/S a disco o red puede tener demoras imposibles de prever. Los hilos de ejecución permiten asegurar que la demora de E/S no demora otras partes no relacionadas con esto en tu aplicación.

Todos estos ejemplos tienen una cosa en común: En el programa, algunas operaciones incurren en una potencial demora o sobrecarga del microprocesador, pero esta demora es inaceptable para otras operaciones; ellas necesitan estar disponibles ya. Por supuesto, hay otros beneficios y estos son:

  • Hacer uso de sistemas multiprocesador: No puedes esperar que una aplicación con sólo un hilo de ejecución haga uso de dos o más procesadores. El capítulo 3 explica esto con más detalles.
  • Compartir el tiempo con eficiencia: Usar hilos de ejecución y prioridades en los procesos asegura una correcta justa del tiempo del microprocesador.

El uso adecuado de los hilos de ejecución convierte a lentas, duras y no muy disponibles aplicaciones en unas que tienen una brillante respuesta, eficiencia y velocidad, además de que puede simplificar radicalmente varios problemas de performance y usabilidad.

Marin Harvey -