II Administración de Procesos y del Procesador Procesos El concepto de proceso es fundamental para la estructura de un sistema operativo, ya que éste consiste básicamente en una colección de procesos. Estos se dividen entre aquellos que ejecutan el código del sistema y los que ejecutan el código de los usuarios. Un proceso (también denominado tarea o trabajo) se suele definir como un programa en ejecución, en el cual las diferentes instrucciones se ejecutan de forma secuencial. Sin embargo, un proceso es algo más que un programa binario ejecutable. También se puede definir un proceso como un espacio de direcciones más una actividad. Un espacio de direcciones no es más que una colección de regiones de memoria virtual, cada una de las cuales tiene ciertas propiedades (tamaño, atributos - lectura, escritura o ejecución- y si puede crecer hacia arriba o hacia abajo del espacio de direcciones virtual). La actividad del proceso está representada por el contenido del registro contador de programa y los contenidos del resto de los registros del CPU. El espacio de direcciones de un proceso suele constar, al menos, de tres regiones: código, datos y pila (stack). La región de código contiene el código ejecutable del proceso, tiene tamaño fijo y es de sólo lectura. Esta última característica permite que una misma región de código pueda ser compartida por más de un proceso que sea instancia de un mismo programa. La región de datos contiene las variables globales del proceso y también se utiliza para asignar memoria a las estructuras de datos dinámicas, por lo que suele crecer hacia las direcciones virtuales más altas. Por último, la región de pila contiene datos temporales, tales como los parámetros, direcciones de retorno y variables locales de los procedimientos invocados. Crece hacia las direcciones virtuales inferiores. Un proceso también es la unidad que puede poseer recursos. Los archivos, memoria, canales de entrada/salida, etc. son asignados por el sistema operativo a los procesos. Representación de los Procesos El núcleo administra los procesos que se ejecutan en el sistema, por lo que debe de usar algún tipo de estructura de datos que constituya la representación física de todos los procesos. Cada proceso se puede representar mediante un descriptor de proceso (también conocido como bloque de control o vector de estado), que es una estructura que contiene información relevante acerca del proceso. La información que almacena un descriptor de proceso es la siguiente: • Identificador de proceso, que constituye un nombre único por el que un proceso es reconocido. • Estado del proceso. • Información que hay que almacenar cuando se le quite el CPU al proceso y que es necesaria para poder re ejecutar posteriormente dicho proceso: o Contador de programa. o Registros del CPU (acumuladores, apuntador de la pila, etc.). o Información relativa a la administración de memoria (registros base y límite, tabla de páginas, etc.). •Información para la planificación (prioridad del proceso) • Información estadística (uso de CPU, etc.). Normalmente, existe una tabla en el núcleo llamada tabla de procesos (PCB), que permite acceder a los descriptores de los procesos. Estados de un Proceso Un proceso puede estar en tres estados básicos: Ejecución: el proceso está siendo ejecutado por un procesador. pág. 1 Bloqueado: un proceso no se puede ejecutar porque está esperando la ocurrencia de un determinado suceso (por ejemplo, la finalización de una operación de entrada/salida). Listo: el proceso está listo para ser ejecutado por un procesador. Algunos motivos por los que un proceso puede ser creado son los siguientes: • Un nuevo usuario se conecta al sistema. • El sistema operativo crea un proceso para que realice un determinado servicio. • Un proceso puede crear otros procesos. • Es el siguiente trabajo de un procesamiento por lotes (batch). Las causas por las que un proceso termina pueden ser las siguientes: • El proceso ejecuta una llamada al sistema indicándole que ha terminado. • El proceso requiere más memoria de la que el sistema puede suministrarle. • Se excede un límite de tiempo. • Errores de protección, aritméticos, intento de ejecutar instrucciones no existentes o no permitidas en modo usuario, etc. • El operador del sistema o el usuario decide eliminar el proceso. Los motivos por las que un proceso se puede ser suspendido o bloqueado son: • El sistema operativo lleva el proceso a disco (swapping) para permitir la ejecución de otros procesos. pág. 2 • El sistema operativo suspende el proceso por varios motivos. Por ejemplo, el proceso puede estar involucrado en una situación de interbloqueo. • El usuario puede suspender la ejecución de un proceso por motivos de depuración. • Un proceso se puede ejecutar de forma periódica y debe esperar hasta que llega el siguiente intervalo. • Un proceso hijo se puede suspender a causa de su proceso padre. Planificación de Procesos Uno de los objetivos del núcleo es la planificación de los procesos del sistema. Normalmente, existe un proceso dedicado a esa tarea denominado planificador de bajo nivel o dispatcher. Este proceso suele estar en estado bloqueado, y es despertado periódicamente, dependiendo del esquema de planificación, o cuando el proceso en ejecución no puede continuar y pasa a estado bloqueado. Procesos e Hilos (threads) En los sistemas operativos tradicionales, el concepto de proceso incluye dos características: • Unidad a la que se le asigna recursos: espacio de direcciones, canales de entrada/salida, canales de comunicaciones, archivos, etc. • Algunos sistemas operativos manejan múltiples hilos de control dentro de un proceso. • También se les conoce como procesos ligeros. • Los hilos comparten el mismo espacio de direcciones. Pero, si un hilo se bloquea, los demás hilos aún pueden ejecutarse incluso mientras se está efectuando E/S de disco. • Es necesario tener una tabla de hilos aparte de la de procesos. Entre los elementos que son distintos para cada hilo están el contador de programa, los registros y el estado Los procesos son entidades que son relativamente costosas de crear y manipular por parte del sistema operativo. En cambio, los hilos comparten los recursos de los procesos y su manipulación es mucho menos costosa que la de éstos. La principal ventaja de tener varios hilos de ejecución es permitir la ejecución concurrente de actividades relacionadas dentro de un proceso. De este modo. Como los hilos de un proceso comparten el mismo espacio de direcciones, no existe ningún tipo de protección por parte del sistema operativo ante el hecho de que una hebra pueda leer o escribir en la pila de otra. Sin embargo, esta protección no debería de ser necesaria, ya que mientras que los procesos pueden pertenecer a varios usuarios, los hilos de un proceso pertenecen a un mismo usuario, por lo que se asume que estarán diseñadas para colaborar, no para competir. Esto no significa que exista la necesidad de proporcionar mecanismos para que los hilos de un proceso se puedan sincronizar. La programación de procesos multihilo se ajusta a la programación concurrente sobre sistemas que comparten memoria, por lo que suelen usar semáforos o monitores para sincronización, aunque también existen sistemas que incorporan primitivas de paso de mensajes. Comunicación y Sincronización entre Procesos Los sistemas operativos se componen de un conjunto de procesos concurrentes, algunos de los cuales necesitan comunicarse y sincronizarse entre sí. El estudio de la comunicación y sincronización entre procesos se engloba en una disciplina conocida como programación concurrente, que tiene su origen en los sistemas operativos. pág. 3 Los sistemas operativos primitivos usaban una técnica llamada procesamiento por lotes (batch) para el procesamiento de tareas. Esta técnica consiste en generar una cola de trabajos, los cuales serán ejecutados uno tras otro, según en el orden en el que aparezcan en la cola. Cuando un proceso necesita realizar una operación de entrada/salida, el CPU permanece inactivo hasta que dicha operación finaliza. El problema del procesamiento por lotes radica en las diferencias de velocidad entre los dispositivos de entrada/salida y los componentes electrónicos de las computadoras, que hacen que la ejecución en serie de procesos desaproveche la mayor parte del tiempo de CPU disponible. Por este motivo, aparece la multiprogramación, que consiste en la posibilidad de ejecutar un proceso de forma concurrente con las operaciones de entrada/salida de otro proceso. Con multiprogramación, en la memoria principal se cargan varios procesos, uno de los cuales se elige para su ejecución. Cuando este proceso realiza una operación de entrada/salida, se bloquea y se elige otro proceso para su ejecución. Si el número de procesos en memoria es lo suficientemente elevado, el CPU del sistema estará activo durante el 100% del tiempo. Posteriormente, se generaliza el concepto de multiprogramación dando lugar al time-slicing o reparto del tiempo, que consiste en compartir el tiempo de procesador entre varios procesos, independientemente de que el proceso que está en ejecución esté realizando una operación de entrada/salida. La forma de realizar este reparto la determina la estrategia de planificación del sistema operativo. De esta forma, las instrucciones de varios procesos se ejecutan de forma entremezclada (interleaving). El time-slicing da lugar a sistemas interactivos de tiempo compartido (time-sharing), mediante el que cada usuario puede utilizar una terminal para utilizar una computadora de forma interactiva. Por otro lado, se dice que un sistema operativo es multitarea cuando es capaz de ejecutar más de un proceso de forma concurrente. Por consiguiente, todo sistema operativo que incorpore multiprogramación o reparto de tiempo es multitarea. Se distinguen dos tipos de multitarea: • Multitarea no apropiativa (non-preemptive multitasking): los procesos se apropian del CPU, de forma que el sistema operativo únicamente puede ejecutar otro proceso cuando el que tiene el CPU realiza una operación de entrada/salida o la libera de forma voluntaria. Un ejemplo de sistema con este tipo de multitarea es Windows 3.1. • Multitarea apropiativa (preemptive multitasking): el sistema le puede quitar el CPU al proceso en ejecución para asignárselo a otro. Ejemplos de sistemas operativos con multitarea apropiativa son UNIX y Windows NT. En la actualidad, aparecen nuevos conceptos que se aplican a los sistemas operativos y que tienen relación con la concurrencia o programación concurrente, como son el multiprocesamiento y el procesamiento distribuido. El multiprocesamiento que permite la ejecución de varios procesos sobre diferentes procesadores. Aunque las computadoras con varios procesadores se restringían hasta hace poco tiempo a supercomputadoras y mainframes, en la actualidad es factible la construcción de computadoras personales y estaciones de trabajo con varios procesadores y con un costo reducido. Windows NT es un sistema operativo que se ejecuta sobre estas computadoras y tiene capacidad de multiprocesamiento. Por último, mediante procesamiento distribuido se pueden ejecutar varios procesos sobre un sistema distribuido, que es una colección de computadores independientes interconectados entre sí. Sobre sistemas distribuidos aparecen los sistemas operativos de red y los sistemas operativos distribuidos. La principal diferencia entre ambos es que en los primeros los usuarios son conscientes de la existencia de varias computadoras, mientras que en los segundos todo el sistema distribuido aparece a los usuarios como un sistema monoprocesador tradicional. pág. 4 Principios de Concurrencia En los sistemas monoprocesador con multitarea los procesos se entremezclan o intercalan en el tiempo para dar la sensación de ejecución simultánea. En los sistemas basados en multiprocesamiento y procesamiento distribuido las instrucciones de los procesos no sólo se entremezclan, sino que también se solapan en el tiempo (overlapping). Sin embargo, tanto la intercalación como el solapamiento son ejemplos de procesamiento concurrente, por lo que ambos presentan los mismos problemas. En cualquier caso, la principal causa de dificultades viene dada por el hecho de que la velocidad relativa de ejecución de los procesos no puede predecirse, ya que intervienen muchos factores: llegada de interrupciones, política de planificación del sistema operativo, interacción entre varios procesos, etc. Los procesos que se están ejecutando en un instante dado, independientemente de que la computadora tenga uno o varios procesadores, pueden interactuar entre sí de dos formas diferentes: • Competición: los procesos pueden competir por un mismo recurso. Ejemplo: dos procesos que intentan imprimir documentos a la vez sobre una misma impresora. En este caso, el sistema operativo deberá proporcionar los medios necesarios para que los documentos se impriman enteros, uno detrás de otro, sin que se impriman líneas entremezcladas de documentos diferentes. • Cooperación: los procesos necesitan intercambiar información entre ellos por algún motivo. Ejemplo: si existe un proceso dedicado a la impresión de documentos sobre una impresora, otro proceso que quiera imprimir tendrá que comunicarse con el primero para indicarle el documento a imprimir. La interacción entre procesos requiere la sincronización entre ellos, es decir, llegar a un punto en el que tiene que ponerse de acuerdo sobre la ocurrencia de cierto suceso. Sección Crítica El acceso a recursos compartidos por parte de más de un proceso puede dar lugar a comportamientos de competencia debido a la intercalación y al solapamiento. Para evitar estos comportamientos no deseados se distinguen dentro de cada proceso aquellas zonas de código que usan recursos compartidos de las que no lo hacen. Estos trozos de código se denominan sección crítica. Si se consigue que únicamente un proceso pueda estar a la vez en su sección crítica se evita el problema. Sin embargo, esto no es suficiente. Una solución satisfactoria debe de cumplir, al menos, las siguientes condiciones (problema de la exclusión mutua): • Dos procesos no pueden estar a la vez dentro de sus secciones críticas (condición de exclusión mutua). • Un proceso que está fuera de su sección crítica no debe interferir con otros procesos. • Un proceso no puede permanecer siempre a la espera de entrar en su sección crítica (indefinida o interbloqueo). • En ausencia de competición, un proceso que desee entrar en su sección crítica lo hará a un costo • No se establecen condiciones acerca de las velocidades de los procesos o número de procesadores del sistema. • Se asume que un proceso permanece en su sección crítica durante un tiempo finito. El control de la competición entre procesos involucra al sistema operativo, ya que éste es la entidad que asigna recursos a los procesos. Además, los procesos deben de expresar sus requerimientos de exclusión mutua de alguna forma. Algunos de estos mecanismos son: semáforos, monitores, contadores de sucesos y paso de mensajes. pág. 5 Definición de términos Como en cualquier área de computación, aquí hay términos propios los cuales se necesitan entender. Esta sección da una introducción a ellos. Programación concurrente: Un programa concurrente consiste en una colección de procesos secuenciales autónomos, ejecutándose (lógicamente) en paralelo. Ejecución Secuencial Un ejemplo ilustrativo. Con disculpas para las abuelitas… Tu abuelita ha decidido que te tejera un suéter para el día de tu cumpleaños. Para tejer un suéter, ella compra un patrón, algo de estambre y agujas. Sigue el patrón paso a paso hasta que esté terminado. Las acciones de tu abuelita para tejer un suéter se muestran en la figura (manga derecha, manga izquierda, espalda, frente y cosido de las partes) y se denomina secuencial porque ocurren en un estricto orden temporal y el siguiente paso nunca se intentara hasta que el paso anterior se haya terminado. Durante nuestras actividades diarias, como cocinar, escribir, manejar, etc., se describen normalmente como una secuencia de paso a realizar, cuando en realidad tenemos que hacer muchas cosas al mismo tiempo para poder realizarlas. Nuestro problema es que no estamos acostumbrados a describir nuestras acciones en términos de concurrencia. Nos forzamos nosotros mismos a ordenar cada acción. Ejecución Paralela Vayamos más allá del problema... Cuando tu abuelita decidió hacerte el suéter para tu cumpleaños, pensó que para no aburrirse y reducir su trabajo iría al club de tejido "EL GATO" donde siempre hay gente esperando trabajo que hacer. Entonces, toma su patrón, su estambre, y agujas suficientes. Va al club y ve que hay gente esperando por trabajo, y comparte el trabajo entre ella y estas personas. pág. 6 Ahora tenemos la ejecución paralela del patrón, Dos abuelitas trabajan al mismo tiempo para completar el trabajo. Hay un número de ventajas obvias en la ejecución en paralelo: • Reduce el tiempo para completar el trabajo • Reduce el esfuerzo individual. Sin embargo también trae muchas desventajas: • La necesidad de compartir el trabajo de manera efectiva. Tu abuelita debe conocer que otras personas están disponibles y dividir el trabajo entre ellas. Si el trabajo no se reparte de forma justa, una abuelita puede terminar más rápido que otra y puede estar mucho tiempo sin hacer nada. • La necesidad de compartir recursos. Puesto que solo hay una bola de estambre y dos agujas, tu abuelita necesita hacerse de más agujas y estambre. Aunque pudiera hacerse, no hay garantía de que puedan ser suficientes. En este caso las abuelitas tendrán que compartir las agujas y el estambre disponible. • La necesidad de esperar por otros en puntos clave. Cuando las abuelitas han terminado sus partes, podrán coser el suéter en un orden en particular. Entonces tendrán que esperar que las piezas estén disponibles en ese orden o que todas las piezas estén disponibles. • La necesidad de comunicación. Cuando las abuelitas han terminado sus partes, tendrán que pasar sus pedazos a la abuelita asignada para coser el suéter. • La necesidad de manejarse con fallas. Si una abuelita se duerme a mitad de su trabajo, entonces ese trabajo se tiene que asignar a otra persona para poder terminar el suéter. El trabajar con esto, requiere de saber cuándo una abuelita se ha dormido y corregir todo lo que esto traiga consigo. Ejecución Concurrente Un enfoque alternativo para el problema del tejido... En lugar de conseguir otras abuelitas para ayudar, se debe tomar otro enfoque para que tu abuelita no se aburra. Obtiene un reloj con alarma, y decide que hará cada una de las cuatro partes básicas del patrón por cinco minutos en cada una. Continua haciendo cambios en las piezas y reiniciando la alarma del reloj pág. 7 para que le indique los cinco minutos de trabajo en cada pieza. Con esta rotación poco a poco va tejiendo el suéter por completo. Esta es una ejecución concurrente. Se denomina así porque todos los trabajos están en mano al mismo tiempo, pero no todos se necesitan ser operados al mismo tiempo. Pudiera parecer que la ejecución concurrente es más complicada que la ejecución secuencial y aun más, no ofrecer ninguna ventaja sobre la ejecución paralela. Sin embargo hay un número de razones por las cuales preferiríamos esta ejecución concurrente con respecto a las otras formas. Estas razones son: • La implantación no está restringida por un tipo de arquitectura de hardware en particular. • Hay menor consideración en el problema de las fallas. • Se satisfacen por completo aquellas demandas donde la velocidad muy alta de procesamiento no se requiere. Entonces le ejecución concurrente es útil porque provee todo el poder conceptual de paralelismo sin la limitante de implantación de hardware que se pudieran imponer. Sin embargo los siguientes problemas aún persisten: • La necesidad de compartir recursos de forma eficiente. La abuelita debe dividir el trabajo de manera sensata. Una parte muy grande provocaría que se terminaran otras primero y desperdiciar ese tiempo del reloj que se les asigno. • La necesidad de compartir recursos. La abuelita debe tener suficientes bolas de estambre y agujas para poder hacer los pasos al mismo tiempo. Si no tiene suficientes, tendrá que elaborar una estrategia de que cuando se mueva de una parte a la otra, y después regrese, el trabajo no se haya destruido. • La necesidad de esperar en puntos clave. Aunque la abuelita no estará "esperando por sí misma" está claro que todas las partes se deben de tejer antes de empezar a coserlas. La abuelita de de llevar de alguna manera un registro de cómo van los trabajos. • La necesidad de comunicación. La abuelita tendrá que comunicarse con sí misma para guardar que paso es en el que esta y cuál es el siguiente. Paralelo contra concurrente Diferencias: Se dice que dos procesos se están ejecutando en paralelo si en determinado tiempo ambos se están ejecutando. Se dice que dos procesos son concurrentes si tienen el potencial de ser ejecutados en paralelo pág. 8 "La programación concurrente es importante porque provee una inicialización abstracta en la cual se puede estudiar paralelismos sin tener que meterse en los detalles de implementación." Una implementación pudiera proveer concurrencia verdadera si la computadora que la está soportando es una multicomputadora o una mutiprocesador, o se simulara concurrencia con multiprogramación (ejecución interfoliada). De cualquier forma que sea la concurrencia, real o verdadera, no afecta los resultados de la ejecución de un programa concurrente. Procesos y procesadores Proceso: Un programa que es capaz de ejecutarse en paralelo. Un proceso no necesita ser físicamente un programa, pero puede ser un componente de un programa. Los procesos varían en tamaño dependiendo del sitio que lo soportara y el área de aplicación. Procesador: Un dispositivo de hardware capaz de ejecutar un proceso. La cantidad de poder de procesamiento disponible puede variar. Algunas maquinas multiprocesador contienen procesadores los cuales tiene una cantidad de procesamiento muy limitada y acceso a una pequeña parte de la memoria. Taxonomia de Flynn(1972) de los sistemas de computo. Basada en dos características esenciales: • Número de flujos de instrucciones • Número de flujos de datos • Máquinas SISD o Computadoras uniprocesador tradicionales o Abarcan desde PC’s a “mainframes” • Máquinas MISD o No se ajustan a ningún modelo existente • Máquinas SIMD o Ejecutan una instrucción en paralelo en varios procesadores operando con diferentes datos o Las supercomputadoras caen, en general, en esta categoría • Máquinas MIMD o Esencialmente, un conjunto de computadoras independientes o Cada uno con su contador de programa, sus instrucciones y sus datos o Todos los sistemas distribuidos son MIMD Interbloqueo o Deadlock Introducción La administración de los recursos es una de las principales tareas del sistema operativo. Muchos de los recursos únicamente pueden ser usados por un solo proceso a la vez, como es el caso de las impresoras, dispositivos de cinta, etc. Como consecuencia, todos los sistemas operativos tienen que ofrecer pág. 9 mecanismos que permitan a los procesos acceder de forma exclusiva a determinados recursos. Como consecuencia, cuando un proceso solicita recursos y éstos no están disponibles en ese momento, entra en un estado de espera. En muchas aplicaciones, un proceso puede requerir acceso exclusivo no sólo a un recurso, sino a varios. En sistemas operativos en los que únicamente se ejecuta un proceso a la vez, el proceso simplemente toma todos los recursos que necesita. Sin embargo, en un sistema con multiprogramación, puede suceder que procesos que están en espera de recursos ocupados por otros procesos no cambien nunca de estado, porque los recursos que solicitan están en poder de otros procesos también en espera. A esto se le llama interbloqueo (deadlock. También abrazo mortal o bloqueo mutuo). El interbloqueo se puede definir como sigue: Un conjunto de procesos se encuentra en estado de interbloqueo cuando cada uno de ellos espera un suceso que sólo puede originar otro proceso del mismo conjunto. En un sistema con multiprogramación la utilización de los recursos es un punto clave en la confiabilidad, y desempeño del sistema. Para analizar mejor el concepto de bloqueo veremos muy rápidamente a que se denomina recurso. Un sistema se compone de un número finito de recursos que se distribuyen entre varios procesos que compiten por ellos. Los recursos se dividen en varios tipos, de cada uno de los cuales pueden existir varios ejemplares idénticos: • Físicos: ciclos de CPU, espacio en memoria, dispositivos de E/S (impresoras, unidades de cinta, etc.). • Lógicos: archivos, tablas del sistema, semáforos. Un proceso debe solicitar un recurso antes de usarlo y liberarlo al terminar su uso. Además, un proceso puede solicitar cuantos recursos necesite. Existen dos clases de recursos: expropiables y no expropiables. • Un recurso expropiable (preemptable resource) es aquél que se le puede quitar a un proceso sin que se produzca ningún tipo de malfuncionamiento. Ejemplos son la memoria y el CPU. • Un recurso no expropiable (non preemptable resource), por el contrario, no puede ser quitado a un proceso sin provocar un fallo en el mismo. Un ejemplo es la impresora. Los interbloqueos se suelen producir, en parte, debido al uso de recursos no expropiables. Sin embargo, existen otros sucesos que pueden originar un interbloqueo, como pueden ser los mecanismos de comunicación entre procesos. En el modo de operación normal, un proceso utiliza un recurso de acuerdo con la siguiente secuencia: • Solicitud. Si la solicitud no puede atenderse de inmediato, entonces el proceso solicitante debe esperar hasta que pueda adquirir el recurso. • Utilización. El proceso puede trabajar con el recurso. • Liberación. El proceso libera el recurso. La solicitud y liberación de recursos son llamadas al sistema. Algunos ejemplos son las parejas de llamadas Abrir/Cerrar archivo y Asignar/Liberar memoria. De igual forma, la utilización de recursos sólo puede conseguirse mediante llamadas al sistema, de modo que para cada utilización el sistema operativo comprueba que el proceso que usa el recurso lo había solicitado previamente y ya lo tiene asignado. Una tabla del sistema registra si cada uno de los recursos está libre o asignado y, de estar asignado, a qué proceso. Si un proceso solicita un recurso que ya se encuentra asignado a otro, puede añadirse a la cola de procesos que esperan tal recurso. Condiciones para que se produzca Interbloqueo pág. 10 Un interbloqueo puede surgir si y solo si en un sistema se presentan simultáneamente las siguientes cuatro condiciones: 1. Exclusión mutua. Los recursos compartidos son adquiridos y utilizados de modo mutuamente exclusivo, es decir, por un proceso como máximo en cada momento. 2. Retención y espera. Cada proceso retiene los recursos que ya le han sido asignados mientras espera para adquirir el resto de recursos. 3. No expropiación. Los recursos no se pueden quitar a los procesos. Un recurso sólo puede ser liberado voluntariamente por el proceso que lo retiene. 4. Espera circular. Debe existir una cadena circular de dos o más procesos, cada uno de los cuales espera por uno o más recursos en poder del siguiente miembro de la cadena. La condición de espera circular implica la condición de retención y espera, por lo que las cuatro condiciones no son completamente independientes. Modelación Para modelar los bloqueos se representan a los procesos con círculos y a los recursos con cuadrados y la relación entre ellos se representa mediante una flecha. Así, si la flecha indica la dirección hacia el proceso significa que el proceso tiene asignado el recurso en cambio si la flecha entra en la dirección contraria significa que el proceso solicita la asignación de dicho recurso. Como evitarlos pág. 11 En general las estrategias mediante las cuales los sistemas pueden enfrentar los bloqueos son: • Ignorar el problema • Detección y recuperación Ignorar el problema En general, los investigadores del área se preocupan de los problemas más frecuentes que pueden afectar el comportamiento del sistema. En este sentido, los bloqueos son problemas que se producen con una frecuencia muy baja, por lo tanto, están preocupados de resolver los problemas que suceden con una mayor frecuencia en el sistema. Si se produce 1 bloqueo cada 3 años, por ejemplo, entonces el tiempo y recursos en el estudio, diseño e implementación de las posibles soluciones. Y si por ejemplo, se producen errores frecuentes en el hardware, compiladores y otras acciones del sistema operativo, entonces es más necesario tratar de resolver esos problemas con mayor urgencia. Por ejemplo, en el sistema Unix, se podría dar el caso de la siguiente situación de bloqueo. Suponga, que la tabla de procesos soporta como máximo 100 entradas en ella, y suponga que existen 10 programas que en su código especifica la creación de 12 procesos cada uno de ellos y el diseño de cada uno de los programas contempla la realización del llamado a sistema fork() persistente hasta que sea exitosa, entonces puede darse el caso que cuando cada uno de los programas respectivos entren en ejecución (pasando a ser procesos), creen cada uno de ellos 9 nuevos procesos sin problemas, sin embargo, a estas alturas de la ejecución, ya se tienen 100 procesos en la tabla de procesos (10 procesos padres, mas 9 procesos hijos por cada padre). Luego, cualquiera de los procesos padres que intente crear el siguiente hijo quedara esperando por que el sistema le retorne exitosa la llamada a sistema fork que le permite crear un hijo. De esta manera vemos, que los 10 procesos padres quedan en estado de bloqueo producto que no es posible crear nuevos procesos y quedan por la tanto en condición de espera. Detección y recuperación de bloqueos Detección Otra estrategia que pueden asumir los sistemas es el tratar de detectar cuando se produce un bloqueo y una vez detectado tratar de romperlo y recuperar las condiciones de ejecución normal de los procesos involucrados. Dentro de las posibilidades de detección se cuentan algoritmos que permiten, por un lado detectar los bloqueos en sistemas que manejan un recurso de cada tipo de recurso, es decir, sistemas que poseen una impresora, un plotter, etc. También existen algoritmos que intentan detectar bloqueos cuando el sistema consta de más de un recurso del un mismo tipo. Recuperación: La recuperación de bloqueos se realiza si se ha tenido éxito en la detección. Dentro de la recuperación se contemplan varias posibilidades: Recuperación mediante apropiación: Esta consiste en que una vez detectado el bloqueo el sistema procede a apropiarse del recurso involucrado y se lo entrega a un proceso que lo estuviese solicitando. Sin embargo, esta tarea de apropiación es un tanto delicada, pues depende del recurso involucrado y el proceso; el sistema debe ser criterioso a la hora de decidir a qué tipo de proceso va a quitarle el recurso, lógicamente los procesos que sean importantes para el sistema tendrán mayor posibilidad de quedarse con el recurso y razonablemente los procesos de los usuarios serán los sacrificados. pág. 12 Este tipo de recuperación es prácticamente imposible que no genere algún proceso perjudicado. Considerando que los recursos sean no apropiables. Recuperación mediante roolback: Este mecanismo consiste en que el sistema periódicamente guarda el estado y los recursos que el posea sean almacenados en un archivo distinto. De manera que cuando ocurra un bloqueo el proceso puede volver a unas de sus instancias anteriores. pág. 13 Recuperación mediante eliminación de procesos: Una posibilidad incluye la eliminación de uno de los procesos que está formando la cadena de procesos en donde se genera el bloqueo, de manera de romper el ciclo. Otra posibilidad es que un tercer proceso, que no pertenece a la cadena del ciclo, sea el proceso eliminado. Suponga por ejemplo que un proceso A posee la impresora y espera por un plotter; y un proceso B posee el plotter y espera por la impresora; luego ambos procesos están bloqueados. Si existe un tercer proceso que posee una impresora y un plotter y este es eliminado, entonces el bloqueo de los procesos A y B es roto. Como se pueden prevenir los bloqueos Es casi imposible evadir los bloqueos, pues es muy difícil que el sistema pueda predecir cuales serán las solicitudes de recursos que harán cada uno de los procesos que se ejecutan en el sistema. En general, los sistemas reales evitan los bloqueos mediante la negación de cualquiera de las condiciones de bloqueo mencionadas anteriormente. Luego se tienen 4 posibilidades: • Prevención de exclusión mutua La negación de la condición de exclusión mutua conlleva a que ningún recurso podría ser utilizado en forma exclusiva por un proceso. Sin embargo esto no es posible, pues hay recursos que no pueden ser utilizados simultáneamente para los resultados sean los correctos. Luego, esta posibilidad no es posible de llevar a la práctica en los casos necesarios. • Prevención de detención y espera Una forma de materializar esta prevención es haciendo que los procesos que poseen recursos no esperen por otros. Una forma de lograr esto es exigirle a los procesos que cuando comiencen pidan todos los recursos que van a necesitar, pero en la práctica no es posible, pues la mayoría de los procesos piden dinámicamente los recursos que van necesitando. Otra forma negar esta condición es exigirle a los procesos que poseen un recurso, lo liberen temporalmente cuando requieren la utilización de otro recurso. • Prevención de no apropiación La negación de esta condición no es posible pues la naturaleza del recurso no es posible de cambiar. • Prevención de espera circular Una de las maneras en que se puede eliminar la espera circular es ordenando los recursos numéricamente, con la siguiente regla. Los procesos pueden solicitar los recursos que deseen, pero las solicitudes se deben hacer en orden numérico, de manera que un proceso no puede solicitar recursos cuyo valor numérico sea menor al valor numérico del recurso que posee. La ordenación numérica de los recursos es realizada cuidadosamente por el sistema. Ejemplo pág. 14 Planificación del procesador o Schedulling La planificación del procesador se refiere a la manera o técnicas que se usan para decidir cuánto tiempo de ejecución y cuando se le asignan a cada proceso del sistema. Obviamente, si el sistema es monousuario y monotarea no hay mucho que decidir, pero en el resto de los sistemas esto es crucial para el buen funcionamiento del sistema. Niveles de planificación En los sistemas de planificación generalmente se identifican tres niveles: el alto, el medio y el bajo. El nivel alto decide que trabajos (conjunto de procesos) son candidatos a convertirse en procesos compitiendo por los recursos del sistema; el nivel intermedio decide que procesos se suspenden o reanudan para lograr ciertas metas de rendimiento mientras que el planificador de bajo nivel es el que decide que proceso, de los que ya están listos (y que en algún momento paso por los otros dos planificadores) es al que le toca ahora estar ejecutándose en la unidad central de procesamiento. En este trabajo se revisaran principalmente los planificadores de bajo nivel porque son los que finalmente eligen al proceso en ejecución. pág. 15 Objetivos de la planificación Una estrategia de planificación debe buscar que los procesos obtengan sus turnos de ejecución apropiadamente, conjuntamente con un buen rendimiento y minimización de la sobrecarga (overhead) del planificador mismo. En general, se buscan cinco objetivos principales: • Justicia o Imparcialidad: Todos los procesos son tratados de la misma forma, y en algún momento obtienen su turno de ejecución o intervalos de tiempo de ejecución hasta su terminación exitosa. • Maximizar la Producción: El sistema debe de finalizar el mayor número de procesos en por unidad de tiempo. • Maximizar el Tiempo de Respuesta: Cada usuario o proceso debe observar que el sistema les responde consistentemente a sus requerimientos. • Evitar el aplazamiento indefinido: Los procesos deben terminar en un plazo finito de tiempo. • El sistema debe ser predecible: Ante cargas de trabajo ligeras el sistema debe responder rápido y con cargas pesadas debe ir degradándose paulatinamente. Otro punto de vista de esto es que si se ejecuta el mismo proceso en cargas similares de todo el sistema, la respuesta en todos los casos debe ser similar. Características a considerar de los procesos. No todos los equipos de cómputo procesan el mismo tipo de trabajos, y un algoritmo de planificación que en un sistema funciona excelente puede dar un rendimiento pésimo en otro cuyos procesos tienen características diferentes. Estas características pueden ser: • Cantidad de Entrada/Salida: Existen procesos que realizan una gran cantidad de operaciones de entrada y salida (aplicaciones de bases de datos, por ejemplo). • Cantidad de Uso de CPU: Existen procesos que no realizan muchas operaciones de entrada y salida, sino que usan intensivamente la unidad central de procesamiento. Por ejemplo, operaciones con matrices. • Procesos de Lote o Interactivos: Un proceso de lote es más eficiente en cuanto a la lectura de datos, ya que generalmente lo hace de archivos, mientras que un programa interactivo espera mucho tiempo (no es lo mismo el tiempo de lectura de un archivo que la velocidad en que una persona teclea datos) por las respuestas de los usuarios. • Procesos en Tiempo Real: Si los procesos deben dar respuesta en tiempo real se requiere que tengan prioridad para los turnos de ejecución. • Longevidad de los Procesos: Existen procesos que típicamente requerirán varias horas para finalizar su labor, mientras que existen otros que solo necesitan algunos segundos. Planificación apropiativa o no apropiativa (preemptive or not preemptive) La planificación apropiativa es aquella en la cual, una vez que a un proceso le toca su turno de ejecución ya no puede ser suspendido, ya no se le puede arrebatar la unidad central de procesamiento. Este esquema puede ser peligroso, ya que si el proceso contiene accidental o deliberadamente ciclos infinitos, el resto de los procesos pueden quedar aplazados indefinidamente. Una planificación no apropiativa es aquella en que existe un reloj que lanza interrupciones periódicas en las cuales el planificador toma el control y se decide si el mismo proceso seguirá ejecutándose o se le da su turno a otro proceso. Este mismo reloj puede servir para lanzar procesos manejados por el reloj del sistema. Por ejemplo en los sistemas UNIX existen los 'cronjobs' y 'atjobs', los cuales se programan en base a la hora, minuto, día del mes, día de la semana y día del año. En una planificación no apropiativa, un trabajo muy grande aplaza mucho a uno pequeño, y si entra un proceso de alta prioridad esté también debe esperar a que termine el proceso actual en ejecución. pág. 16 Asignación del turno de ejecución. Los algoritmos de la capa baja para asignar el turno de ejecución se describen a continuación: • Por prioridad: Los procesos de mayor prioridad se ejecutan primero. Si existen varios procesos de mayor prioridad que otros, pero entre ellos con la misma prioridad, pueden ejecutarse estos de acuerdo a su orden de llegada o por 'round robin'. La ventaja de este algoritmo es que es flexible en cuanto a permitir que ciertos procesos se ejecuten primero e incluso, por más tiempo. Su desventaja es que puede provocar aplazamiento indefinido en los procesos de baja prioridad. Por ejemplo, suponga que existen procesos de prioridad 20 y procesos de prioridad 10. Si durante todo el día terminan procesos de prioridad 20 al mismo ritmo que entran otros con esa prioridad, el efecto es que los de prioridad 10 estarán esperando por siempre. También provoca que el sistema sea impredecible para los procesos de baja prioridad. • El trabajo más corto primero: Es difícil de llevar a cabo porque se requiere saber o tener una estimación de cuánto tiempo necesita el proceso para terminar. Pero si se sabe, se ejecutan primero aquellos trabajos que necesitan menos tiempo y de esta manera se obtiene el mejor tiempo de respuesta promedio para todos los procesos. Por ejemplo, si llegan 5 procesos A,B,C,D y E cuyos tiempos de CPU son 26, 18, 24, 12 y 4 unidades de tiempo, se observa que el orden de ejecución será E,D,B,C y A (4,12,18, 24 y 26 unidades de tiempo respectivamente). En la tabla siguiente se muestra en que unidad de tiempo comienza a ejecutarse cada proceso y como todos comenzaron a esperar desde la unidad cero, se obtiene el tiempo promedio de espera. Tiempo promedio = (4 + 16 + 34 + 58 + 84 )/5 = 39 unidades. • El primero en llegar, primero en ejecutarse: Es muy simple, los procesos reciben su turno conforme llegan. La ventaja de este algoritmo es que es justo y no provoca aplazamiento indefinido. La desventaja es que no aprovecha ninguna característica de los procesos y puede no servir para un proceso de tiempo real. Por ejemplo, el tiempo promedio de respuesta puede ser muy malo comparado con el logrado por el del trabajo más corto primero. Retomando el mismo ejemplo que en el algoritmo anterior, obtenemos un tiempo de respuesta promedio (26+44+68+80+84)/5 = 60 unidades, el cual es muy superior a las 39 unidades que es el mejor tiempo posible. Round Robin: También llamada por turno, consiste en darle a cada proceso un intervalo de tiempo de ejecución (llamado time slice), y cada vez que se vence ese intervalo se copia el contexto del proceso a un lugar seguro y se le da su turno a otro proceso. Los procesos están ordenados en una cola circular. pág. 17 Por ejemplo, si existen tres procesos, el A, B y C, dos repasadas del planificador darían sus turnos a los procesos en el orden A, B, C, A, B, C. La ventaja de este algoritmo es su simplicidad, es justo y no provoca aplazamiento indefinido. • El tiempo restante más corto: Es parecido al del trabajo más corto primero, pero aquí se está calculando en todo momento cuánto tiempo le resta para terminar a todos los procesos, incluyendo los nuevos, y aquel que le quede menos tiempo para finalizar es escogido para ejecutarse. La ventaja es que es muy útil para sistemas de tiempo compartido porque se acerca mucho al mejor tiempo de respuesta, además de responder dinámicamente a la longevidad de los procesos; su desventaja es que provoca más sobrecarga porque el algoritmo es más complejo. • La tasa de respuesta más alta: Este algoritmo concede el turno de ejecución al proceso que produzca el valor mayor de la siguiente fórmula: Es decir, que dinámicamente el valor se va modificando y mejora un poco las deficiencias del algoritmo del trabajo más corto primero. • Por política: Una forma de asignar el turno de ejecución es por política, en la cual se establece algún reglamento específico que el planificador debe obedecer. Por ejemplo, una política podría ser que todos los procesos reciban el mismo tiempo de uso de CPU en cualquier momento. Esto significa, por ejemplo, que si existen 2 procesos y han recibido 20 unidades de tiempo cada uno (tiempo acumulado en time slices de 5 unidades) y en este momento entra un tercer proceso, el planificador le dará inmediatamente el turno de ejecución por 20 unidades de tiempo. Una vez que todos los procesos están 'parejos' en uso de CPU, se les aplica 'round robin'. I pág. 18