Mostrando entradas con la etiqueta Multitasking. Mostrar todas las entradas
Mostrando entradas con la etiqueta Multitasking. Mostrar todas las entradas

Multitarea – Condiciones de carrera



Las condiciones de carrera (Race Condition o Race Hazard en inglés) es un problema de diseño propio de los sistemas multitarea. Diferentes tareas o proceso compiten por determinados recursos compartidos y en ocasiones pueden provocar la caída del sistema o una mala experiencia de usuario.

Intentemos explicar las condiciones de carrera con una carrera de caballos.



Imaginemos que una carrera de caballos, todos los jinetes intentan cabalgar por el carril mas interno.

El carril más interno de la pista de carreras es un recurso compartido, puesto que puede ser ocupado por cualquiera de los jinetes en un momento dado.

Pero el uso de este carril, implica que al ser uno solo, los jinetes compitan por ocuparlo y esa competencia tiene que tener determinada sincronización.

Una vez ocupado este carril, puedes correr a toda velocidad si no tienes ningún caballo delante, o correr teniendo en cuenta la velocidad del o los caballos que tengas delante en el mismo carril.

Otro problema es que dos caballos no pueden ocupar el mismo carril a la vez en la misma posición porque se produciría una colisión que podría traer como consecuencia la caída de caballos y jinetes.

La única solución que tiene un jinete en una carrera de caballos para utilizar este carril es la sincronización:

  • Si está vacío, puedes ocuparlo a toda velocidad y correr mientras no tengas nadie delante
  • Si está ocupado, tienes que ir a una velocidad inferior a la de los caballos que tengas delante
  • Si vas a entrar o a salir del carril, tienes que cuidar que no haya colisión con otros caballos

Un problema similar ocurre con los ordenadores y teléfonos móviles. Imaginemos que el carril es un recurso compartido, por ejemplo el micrófono de un teléfono móvil. Los caballos son hilos de ejecución (threads). Como por lo general, el teléfono solo tiene un micrófono, un hilo de ejecución donde se ejecuta una llamada de voz no puede interferir con hilo que ejecuta una grabación de notas de voz.



Y lo mismo pasa con la pantalla. Un juego que presenta animaciones en pantalla, no puede interferir con el uso del visor de la cámara de fotos que utiliza también la pantalla.

Si no sincronizan y se respetan estas acciones, el usuario grabaría una conversación de voz que no sería transmitida al otro interlocutor a través de la red telefónica, o el juego continuaría enviando imágenes animadas a una pantalla por donde tenemos que mirar antes de hacer una foto.

Las condiciones de carrera en un sistema informático se producen siempre cuando varios procesos o tareas acceden a un recurso compartido (memoria, disco, dispositivo de entrada / salida) cambiando temporalmente su estado que es reportado a otro proceso como un error. Por ejemplo que se grabe una conversación de voz en vez de trasmitirse a la voz a otro usuario.

Otra condición de carrera se produce cuando un proceso descarga un archivo de música o vídeo desde Internet y otro proceso intenta reproducirlo al mismo tiempo. 



El proceso que reproduce tiene que tener dos facilidades implementadas:

  • Buffering (a almacenamiento temporal) de los datos que desea reproducir. El proceso de descarga transfiere bloques de datos a este buffer bloqueándolo durante un corto espacio de tiempo y luego liberándolo para que el proceso reproductor lo pueda leer
  • Mecanismo para sincronizar cuando el buffer tiene datos disponibles o cuando se han terminado los datos o simplemente cuando no se actualiza el buffer durante un período de tiempo demasiado grande

Si no hay buffering, el proceso que reproduce puede intentar leer un fichero que puede estar bloqueado por el proceso de descarga. Esto implicaría que nuestra aplicación tendría que esperar terminar la descarga antes de reproducir su contenido.

Si no hay sincronismo entre procesos, el que reproduce fallará porque el buffer podría estar en uso por el proceso de descarga.

Multitarea - Conceptos básicos


Conceptos básicos

Se refiere a la capacidad de un sistema operativo de ejecutar múltiples procesos, también llamados tareas, dándole al usuario o los usuarios la impresión de que son ejecutados simultáneamente y sin interferir los unos con los otros.

Cada tarea al ejecutarse, es como si fuera la única dentro del sistema que se está ejecutando y con acceso a todos los recursos y servicios que nos brinda el sistema operativo.

Los procesos que se ejecutan de forma concurrente (al mismo tiempo) pueden representar:

  • Programas diferentes
  • Partes diferentes de un mismo programa
  • Diferentes instancias de un mismo programa (cada instancia es una copia en ejecución del mismo programa)

El número tal de tareas o procesos que pueden ejecutarse en un sistema depende de varios factores entre los que se incluyen:

  • El tamaño de la memoria
  • La velocidad del procesador central (CPU)
  • El tamaño de los programas
  • La tecnología del procesador para soportar la multitarea

Una característica importante del sistema operativo para poder soportar la multitarea es que cada proceso esté protegido del resto de los procesos.

Protegido quiere decir que se ejecuta en un espacio físico y lógico que garantiza su ejecución y que no es alcanzado accidentalmente por ningún otro proceso, no quiere decir aislado completamente (existen formas de comunicar un proceso con otro si es necesario).

Esta protección de procesos realizada a nivel de kernel (núcleo de ejecución del sistema operativo), permite que cuando un proceso se detiene por alguna razón (halt o crash) el resto de los procesos y el propio sistema operativo continúan normalmente con su ejecución.

El procesador (o procesadores) son demandados continuamente en el sistema operativo por numerosos procesos que compiten por sus servicios. Pero como el procesador solo puede ejecutar un proceso al mismo tiempo, la multitarea es acompañada de una técnica de ranuras de tiempo (time slices) que permiten alternar el uso del procesador entre varios procesos a una alta velocidad.


Desde el punto de vista de la ejecución de tareas, los sistemas operativos se dividen en dos grandes grupos:

  • Monotarea: solo ejecutan una tarea al mismo tiempo, por ejemplo el MS-DOS
  • Multitarea: pueden ejecutar simultáneamente múltiples tareas. Aquí se incluyen prácticamente todos los sistemas operativos modernos como Windows XP/7, Mac OSX o UNIX/Linux

En los sistemas operativos monotarea, el CPU permanece ocioso (idle) hasta que el recurso que demanda el programa está disponible (un disco o una impresora por ejemplo). Esta espera es una pérdida de tiempo de proceso y de eficiencia del sistema.

En un sistema multitarea, múltiples procesos se mantienen en la memoria, permitiendo al sistema operativo cambiar a otro proceso mientras el sistema actual tiene que esperar por los periféricos de entrada / salida para completar una tarea.

La multitarea puede realizarse de dos maneras diferentes:

  • Cooperativa (cooperative multitasking)
  • Preventiva o preferente (Preemptive multitasking)

En el caso de la multitarea cooperativa, las tareas ceden voluntariamente el control a otras tareas para que estas se puedan ejecutar. Sin embargo, si una tarea se excede en tiempo por algún fallo, el resto de las tareas pueden quedarse sin tiempo de ejecución y provocar una paralización total del sistema que puede llegar incluso a su caída. Ejemplo de sistemas operativos con multitarea cooperativa son el Windows 3.X o el Mac OS versión 8.0.

En la multitarea preventiva, las tareas delegan en el sistema operativo el tiempo de ejecución disponible para cada una de ellas. Así si una tarea se queda bloqueada o se detiene por alguna razón, el sistema operativo le quita el control asignando tiempo de ejecución al resto de las tareas y evitando que el sistema en su conjunto pueda quedarse bloqueado o se caiga fácilmente.

También es necesario distinguir entre multitarea y multiprocesamiento. La multitarea se refiere a la habilidad de ejecutar varias tareas al mismo tiempo. El multiprocesamiento es una capacidad del sistema operativo de utilizar más de un procesador al mismo tiempo, si el hardware lo permite.

Típicamente, si hay disponibles múltiples procesadores, las tareas pueden ser divididas entre ellos. En tal caso, las tareas pueden ejecutarse simultáneamente, reduciendo el tiempo de ejecución total y dando un gran rendimiento al sistema.

Si solo hay un procesador, a las tareas no les queda otro camino que compartirlo y al sistema operativo asignarles el tiempo de ejecución que les toca.


Orígenes de la multitarea


La multitarea se originó en los años 60, cuando los sistemas de tiempo compartido fueron desarrollados como una alternativa para abaratar los costes de explotación de los grandes ordenadores (mainframes), permitiendo su uso por múltiples usuarios.

En los sistemas de tiempo compartido, el sistema operativo asignaba un tiempo a cada de uno de los usuarios conectados por terminales al ordenador central. Si los cambios eran lo suficientemente rápidos, el usuario conseguía la ilusión de estar él solo conectado al ordenador central, como si no hubiese otros usuarios conectados.

A su vez el sistema de tiempo compartido desarrolló los primeros algoritmos para que un usuario pudiera tener su propia zona protegida de memoria y el acceso a recursos compartidos del sistema sin interferir en el trabajo de otros usuarios.

Pronto se hizo evidente que esta misma técnica de tiempo compartido, podía aplicarse a los procesos o tareas ejecutados por un mismo usuario. Con un hardware más potente,  fue más fácil que los usuarios pudieran ejecutar a la vez varios procesos, haciendo un uso más óptimo del sistema y del ordenador.

De esta manera el término “tiempo compartido” (time sharing) fue sustituido por un término más genérico: multitarea (multitasking), teniendo en cuenta que cada una de las conexiones de usuario representaban a su vez tareas para el proceso operativo.

De esta forma, cada usuario conectado abría una tarea de usuario. A su vez cada usuario dentro de su tarea de usuario, podía ejecutar varias tareas o procesos de manera simultánea.

IBM fue uno de los líderes en implementar los primeros sistemas operativos multitarea, tales como el OS/360 y OS/370. Aun hoy en día su entorno interactivo multitarea se sigue llamando TSO (Time Sharing Option) incluso para los sistemas más recientes como MVS, OS/390 y z/OS.

Otro centro importante en el desarrollo de los sistemas operativos multitarea fueron los laboratorios Bell, los creadores del sistema operativo UNIX entre 1969 y1972.

El sistema operativo UNIX fue muy famoso por ser el primer sistema escrito en lenguaje de programación C y en ser explotado no solo comercialmente sino por instituciones científicas y universitarias. Miles de horas de entusiastas programadores invertidas en su desarrollo, le convirtieron en el padre de numerosos sistemas operativos modernos tales como AIX, Solaris, Linux o Mac OSX.

Por último, la multitarea es particularmente importante en los llamados sistemas operativos de tiempo real (real time operating systems o RTOS), muy utilizados en sistemas empotrados (embedded systems) mayoritariamente de uso industrial.

En estos sistemas, se hace necesario monitorizar y controlar varias tareas de manera prácticamente instantánea. Estos sistemas utilizan un mecanismo de interrupción y un sistema de prioridad de ejecución de procesos, que permite la ejecución de tareas a intervalos de tiempo y con resultados muy cercanos al tiempo real. En estos sistemas los segundos y milisegundos a la hora de completar un determinado proceso cuentan, a diferencia del resto de los sistemas operativos multitarea donde esos tiempos de respuesta en muchas ocasiones son despreciables desde el punto de vista de usuario.

Algunos de los sistemas operativos de tiempo real más importantes son: RTLinux, Neutrino o QNX.

Multi-hilos (Multi-threading)

Tan pronto como la multitarea mejoró el desempeño de los ordenadores, los programadores comenzaron a implementar aplicaciones diseñadas como un conjunto de procesos que cooperaban entre si. Por ejemplo, un proceso leía la entrada de datos, otro transformaba los datos de entrada y un tercero los escribía en disco.

Esto requirió algunas herramientas que permitieran que estos procesos pudieran comunicarse entre sí.

Así nacieron los hilos de ejecución o threads, con el objetivo de implementar una vía eficiente de ejecutar procesos que compartieran un único espacio de memoria para intercambiar datos.

Dicho de otra manera, los hilos de ejecución son procesos que se ejecutan en un mismo espacio o contexto de memoria (memory context).

Los hilos se consideran procesos ligeros (lightweight processes) porque los cambios entre un hilo y otro no implican cambiar el contexto de memoria.

Los distintos hilos de ejecución comparten una serie de recursos tales como el espacio de memoria, los archivos abiertos, situación de autenticación, etc. Esta técnica permite simplificar el diseño de una aplicación que debe llevar a cabo distintas funciones simultáneamente.

Normalmente los hilos se crean como subprocesos o lo que es lo mismo suelen depender de un proceso principal.

El proceso sigue en ejecución mientras al menos uno de sus hilos de ejecución siga activo. Cuando el proceso finaliza, todos sus hilos de ejecución también han terminado. Asimismo en el momento en el que todos los hilos de ejecución finalizan, el proceso no existe más y todos sus recursos son liberados.

Algunos lenguajes de programación tienen características de diseño expresamente creadas para permitir a los programadores lidiar con hilos de ejecución (como Java, Delphi o FreePascal).

Otros (la mayoría) desconocen la existencia de hilos de ejecución y éstos deben ser creados mediante llamadas de biblioteca especiales que dependen del sistema operativo en el que estos lenguajes están siendo utilizados (como es el caso del C , C++ o Microsoft .NET C#).

Un ejemplo de implementación con hilos es la carga de una página Web en un navegador. Mientras un hilo atiende a los botones y controles de la interfaz de usuario, otro hilo en paralelo descarga el texto y las imágenes del sitio Web remoto y un tercer hilo las va pintando en la pantalla.

Fibras


Mientras que los hilos son ejecutados mediante multitarea preventiva (preemptive multitasking), algunos sistemas operativos ofrecen una variante de hilos denominada fibras (fiber) que se ejecutan de manera cooperativa.

Las fibras son unidades de ejecución aún más ligeras que los hilos. Una fibra en ejecución debe ceder o permitir explícitamente la ejecución de otra fibra. Eso es más simple que implementar hilos a nivel de kernel o a nivel de usuario.

Esto permite que las aplicaciones puedan administrar por ellas mismas la multitarea, en vez de utilizar el planificador del kernel (kernel scheduler).

Algunos sistemas de programación en paralelo como OpenMP (Open Multiprocessing) utilizan de manera intensiva las fibras.


Bibliografía



Entradas antiguas Inicio