Professional Documents
Culture Documents
PROGRAMACIN CONCURRENTE
7 Programacin concurrente. ............................................................................................ 2 7.1 La nocin de proceso ............................................................................................. 2 7.1.1 Construcciones de programacin concurrente ............................................... 4 7.2 Ejecucin concurrente............................................................................................ 4 7.2.1 Procesos y objetos.......................................................................................... 6 7.3 Representacin de procesos ................................................................................... 7 7.3.1 Corrutinas....................................................................................................... 7 7.3.2 Fork y join...................................................................................................... 7 7.3.3 Cobegin .......................................................................................................... 8 7.3.4 Declaracin explicita de procesos.................................................................. 8
Rafael lvarez Garca ltima revisin 29-10-07 rafpalvarez@gmail.com Nota importante: Este documento no pretende reemplazar al material propuesto por la UNED para la asignatura Sistemas en Tiempo Real. Cualquier sugerenca, comentario o correccin sobre este documento, envelo a rafpalvarez@gmail.com para poder realizar los cambios necesarios.
1
7 Programacin concurrente.
Virtualmente, todos los sistemas de tiempo real son inherentemente concientes. Los lenguajes destinados a ser usados en este dominio tienen mayor potencia expresiva si proporcionan al programador primitivas que se ajusten al paralelismo de las aplicaciones. Denominamos programacin concurrente a la notacin y tcnicas de programacin que expresan el paralelismo potencia] y que resuelven los problemas resultantes de la sincronizacin y la comunicacin. La implementacin del paralelismo es un tena de los sistemas informticos (hardware y software) esencialmente independiente de la programacin concurrente. La importancia de la programacin concurrente esta en que proporciona un entorno abstracto donde estudiar el paralelismo sin tener que enfrascarse en los detalles de implementacin, (Ben-Ari, 1982)
como distribuidos hacia / desde los procesadores disponibles. Estas actividades son efectuadas por el sistema de soporte de ejecucin (RTSS; Run-Time Support System) o ncleo de ejecucin. El RTSS posee muchas de las caractersticas del planificador de un sistema operativo, y esta ubicado, lgicamente, entre el hardware y el software de aplicacin. En realidad, puede tomar una de las siguientes formas: (1) Una estructura software programada como parte de la aplicaci6n (esto es, como un componente del programa concurrente). Esta es la aproximacin adoptada por el lenguaje Modula-2. (2) Un sistema software estndar generado junto al cdigo objeto del programa por el compilador. Esta es la estructura habitual en los programas de Ada y Java. (3) Una estructura hardware micro codificada en el procesador, por motivos de eficiencia. Un programa occam2 que se ejecuta en un transputer tiene este sistema de ejecucin. El algoritmo que utiliza el RTSS para planificar (esto es, para decidir que proceso se ejecuta a continuacin en el caso de haber mas de uno ejecutable) afectara al comportamiento temporal del programa, aunque, para programas bien construidos, el comportamiento lgico no depender del RTSS. Desde el punto de vista del programa, se asume que el RTSS planifica los procesos de forma no determinista. En el caso de los sistemas de tiempo real las caractersticas de la planificacin son relevantes. Todos los sistemas operativos proporcionan mecanismos para crear procesos concurrentes. Normalmente, cada proceso se ejecuta en su propia maquina virtual, para evitar interferencias con otros procesos no relacionados. Cada proceso consta, realmente, de un nico programa. Sin embargo, en los ltimos aos se tiende a permitir la creacin de procesos dentro de los programas. Los sistemas operativos modernos permiten crear procesos dentro del mismo programa accediendo de modo compartido, y sin restricciones, a la memoria comn (estos procesos suelen llamarse hilos o hebras). Por tanto. en los sistemas operativos que se ajustan a POS1X. es preciso distinguir entre la concurrencia de programas (procesos), y la concurrencia dentro de un programa (hilos). tambin es frecuente distinguir entre aquellos hilos visibles desde el sistema operativo y aquellos que provienen nicamente del soporte de ciertas rutinas de biblioteca. Ha habido un amplio debate entre programadores, diseadores de lenguajes y diseadores de sistemas operativos, sobre si lo apropiado es que sea el lenguaje quien de soporte para la concurrencia, o si ste debiera ser proporcionado nicamente por el sistema operativo. Los argumentos a favor de incluir la concurrencia en los lenguajes de programacin son los siguientes: (1) Lleva a programas mas legibles y fciles de mantener. (2) Existen muchos tipos distintos de sistemas operativos; al definir la concurrencia en el lenguaje se consiguen programas mas portables. (3) Puede que el computador embebido ni siquiera disponga de un sistema operativo residente. Claramente, estos fueron los argumentos que mas pesaron sobre los diseadores de Ada y Java. Los argumentos en contra de la concurrencia en el lenguaje son los siguientes: (1) Cada lenguaje tiene un modelo de concurrencia distinto; resulta mas sencillo componer programas de distintos lenguajes si todos utilizan el mismo modelo de concurrencia del sistema operativo. (2) Puede no ser fcil implementar eficientemente cierto modelo de concurrencia de un lenguaje sobre algn modelo de sistema operativo. (3) Comienzan a aparecer estndares de sistema operativo, y por tanto los programas se vuelven mas portables. 3
La necesidad de soportar diversos lenguajes fue una de las principales razones por las que la industria aeronutica civil, al desarrollar su programa de Avionica Modular Integrada, opto por una interfaz de programacin de aplicaciones ncleo estndar (llamada APEX) que soporta concurrencia, en vez de adoptar el modelo de concurrencia de Ada (ARINC AEE Committee, 1999). El debate, sin duda, continuara durante algn tiempo.
Al considerar la interaccin entre procesos, es til distinguir entre tres tipos de comportamiento: Independiente Cooperativo Competitivo
Los procesos independientes no se comunican o sincronizan entre si. Por contra, los procesos cooperativas se comunican con regularidad y sincronizan sus actividades para realizar alguna operacin comn. Un sistema informtico consta de un nmero finito de recursos que pueden ser compartidos entre los procesos; por ejemplo, perifricos, memoria y potencia de procesador. Para que los procesos obtengan su proporcin justa de recursos, deben compear entre si. La asignacin de recursos necesita inevitablemente comunicacin y sincronizacin entre los procesos del sistema. Pero, aunque estos procesos se comuniquen y sincronicen para obtener recursos, son esencialmente independientes.
Esttica: el nmero de procesos es fijo y conocido en tiempo de compilacin. Dinmica: los procesos son creados en cualquier momento. El nmero de procesos existentes solo se determina en tiempo de ejecucin. 4
Otra distincin entre lenguajes proviene del nivel de paralelismo soportado. De nuevo, se pueden identificar dos casos distintos: Anidado: los procesos se definen en cualquier nivel del texto del programa; en particular, se permite definir procesos dentro de otros procesos. Piano: los procesos se definen nicamente en el nivel mas externo del texto del programa.
Dentro de los lenguajes que permiten construcciones anidadas, existe tambin una interesante distincin entre lo que se puede llamar paralelismo de grano grueso y de grano fino. Un programa concurrente de grano grueso contiene relativamente pocos procesos, cada uno con una historia de vida significativa. Por su parte, los programas con paralelismo de grano fino tienen un numero mayor de procesos sencillos, algunos de los cuales existen para una nica accin. La mayora de los lenguajes de programacin concurrentes, representados por Ada, muestran paralelismo de grano grueso. Occam2 es un buen ejemplo de lenguaje concurrente con paralelismo de grano fino. Cuando se crea un proceso, puede ser necesario proporcionar informacin relacionada con su ejecucin (de la misma forma que un subprograma requiere cierta informacin cuando es invocado). Hay dos formas de realizar esta inicializacin: la primera es pasar al proceso la informacin en forma de parmetros; la segunda es la comunicacin explicita con el proceso, despus de que haya comenzado su ejecucin. La finalizacin de procesos se puede realizar de distintas formas. A continuacin se resumen las circunstancias en las que se permite que un proceso finalice: (1) Finalizacin de la ejecucin del cuerpo del proceso. (2) Suicidio por ejecucin de una sentencia de auto finalizacin. (3) Aborto por medio de una accin explcita de otro proceso. (4) Ocurrencia de una condicin de error sin tratar. (5) Nunca; procesos que se ejecutan en bucles que no terminan. (6) Cuando ya no son necesarios. Con la anidacin en niveles, es posible crear jerarquas de procesos y establecer relaciones entre ellos. Para cualquier proceso, es til distinguir entre el proceso (o bloque) que es responsable de su creacin, y el proceso (o bloque) que es afectado por su finalizacin. La primera relacin es conocida como padre / hijo, y posee la caracterstica de que el padre puede ser detenido mientras et hijo se crea e inicializa. La segunda se denominada guardian/dependiente, y en el la un proceso puede depender del propio proceso guardin o de un bloque interno de este. El guardin no puede terminar un bloque hasta que todos los procesos dependientes hayan terminado (esto es, un proceso no puede existir fuera de su alcance). Consecuentemente, un guardin no puede terminar hasta que lo hayan hecho todos sus procesos dependientes. La consecuencia de esta regla es que un programa no podr terminar hasta que todos los procesos creados en el hayan terminado tambin.
En algunas situaciones, el padre de un proceso Ser tambin su guardin. Este ser el caso cuando se utilicen lenguajes que solo permiten estructuras estticas de procesos (por ejemplo occam2). Con estructuras dinmicas de procesos (que tambin son anidadas), el padre y el guardin pueden no ser el mismo. Esto se ilustrara posteriormente cuando se vea Ada. Una de las formas en que un proceso puede finalizar punto (3) de la lista anterior es por la aplicacin de una sentencia que lo aborta (abort). La existencia de abort en los lenguajes de programacin concurrentes es una cuestin de cierta controversia. Para una jerarqua de procesos suele ser necesario que la interrupcin de un guardin implique la interrupcin de todos los dependientes (y de los dependientes de estos, y as recursivamente). La ultima circunstancia de finalizacin de la lista anterior se ver con mas detalle al describir los mtodos de comunicacin de procesos. En esencia, permite que un proceso servidor termine si el resto de procesos que podran comunicar con el ya han terminado.
ejemplo un semforo). Pero, para algunas clases de programas, esto puede ser poco flexible, y llevar a estructuras de programa deficientes (esto se discute con mas detalle en el Capitulo 8). Los servidores son esencialmente flexibles, ya que el agente de control se programa mediante un proceso. El inconveniente de esta aproximacin es que puede desembocar en un aumento de procesos y, en consecuencia, en un elevado numero de cambios de contexto durante la ejecucin. Esto es particularmente problemtico si el lenguaje no permite recursos protegidos y hay que utilizar un servidor para cada cantidad.
7.3.1 Corrutinas
Las corrutinas son como subrutinas, salvo que permiten el paso explicito de control entre ellas de una forma simtrica en vez de estrictamente jerrquica. El control se transfiere de una corrutina a otra mediante una sentencia reanuda (resume) que incluye el nombre de la corrutina con la que se continua. Cuando una corrutina realiza una reanudacin, deja de ejecutarse, pero guarda informacin del estado local, de forma que si, posteriormente, otra corrutina la hace reanudar, podr retomar su ejecucin. Cada corrutina puede verse como parte de un proceso separado; sin embargo, no es necesario un sistema de soporte de ejecucin, ya que las propias corrutinas se colocan en orden de ejecucin. Claramente, las corrutinas no son adecuadas para un autentico procesamiento paralelo, ya que su semntica solo permite la ejecucin de una rutina cada vez. Modula-2 es un ejemplo de lenguaje que soporta corrutinas.
El lenguaje Mesa proporciona la notacin fork y join. tambin POSIX proporciona una versin de fork y join; aunque aqu fork sirve para crear una copia del invocador, y el join efectivo se obtiene mediante la llamada del sistema wait. Fork y join permiten crear procesos dinmicamente, y proporcionan un mecanismo para pasar informacin al proceso hijo a travs de parmetros. Normalmente, al terminar el hijo, devuelve un solo valor. Aunque flexibles, fork y join no proporcionan una aproximacin estructurada a la creacin de procesos, y su utilizacin es propensa a errores. Por ejemplo, un proceso guardin debe reunir explcitamente todos los procesos dependientes, en vez de esperar simplemente a que terminen.
7.3.3 Cobegin
Cobegin (o par) es una forma estructurada de denotar la ejecucin concurrente de un conjunto de instrucciones: Cobegin S1; S2; Sn; coend Este cdigo permite la ejecucin concurrente de las instrucciones SI, S2, etc. La instruccin cobegin (comienzo) termina cuando han terminado todas las instrucciones concurrentes. Cada instruccin Si puede ser cualquiera de las construcciones permitidas en el lenguaje, incluyendo las asignaciones sencillas o las llamadas a procedimientos. De invocar algn procedimiento, podrn pasarse datos a los procesos invocados mediante los parmetros de la llamada. La instruccin cobegin podra incluir, a su vez, una secuencia de instrucciones donde apareciera cobegin, y as construir una jerarqua de procesos. Cobegin puede encontrarse en occam2.
proporcionar ejemplos concretos sobre lenguajes de programacin reales, se vera la ejecucin concurrente en occam2, Ada y Java. Complementariamente, se comentara la ejecucin concurrente en POSIX,