capitulo 7. programacion concurrente

Upload: javier-tamargo

Post on 05-Apr-2018

238 views

Category:

Documents


0 download

TRANSCRIPT

  • 7/31/2019 Capitulo 7. Programacion concurrente

    1/9

    1

    CAPTULO 7. 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 Garcaltima revisin [email protected]

    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 [email protected] para poder realizar los cambios necesarios.

  • 7/31/2019 Capitulo 7. Programacion concurrente

    2/9

    2

    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)

    7.1 La nocin de proceso

    Cualquier lenguaje, natural o informtico, tiene un carcter dual: a la vez que es capaz de

    expresarse, tambin limita el entorno en el que se aplica dicha capacidad expresiva. Si un lenguaje no

    permite cierta nocin o concepto particular, entonces aquellos que utilizan el lenguaje no podrn

    emplear este concepto, y puede que, incluso, desconozcan por completa su existencia.

    Pascal, C, FORTRAN y COBOL comparten la propiedad comn de ser lenguajes de programacin

    secuenciales. Los programas escritos en estos lenguajes tienen un nico hilo de control. Comienzan la

    ejecucin en cierto estado y avanzan ejecutando una sentencia cada vez, hasta que el programa

    finaliza. La traza a travs del programa puede diferir debido a variaciones en los datos de entrada,

    aunque para una ejecucin concreta del programa existe una nica traza. Esto no es lo adecuado para la

    programacin de sistemas de tiempo real. Un programa concurrente puede verse como un conjunto de

    procesos secuenciales autnomos, que son ejecutados en paralelo. Todos los lenguajes de

    programacin concurrente incorporan, explicita o implcitamente, la nocin de proceso; cada. proceso

    tiene un hilo de control.

    La implementacin real (esto es, la ejecucin) de un conjunto de procesos tiene lugar normalmente

    de tres formas. Los procesos pueden;

    (1) Multiplexar sus ejecuciones sobre un nico procesador.

    (2) Multiplexar su ejecuciones en un sistema multiprocesador con acceso a memoria

    compartida.

    (3) Multiplexar sus ejecuciones en diversos procesadores que no comparten memoria (a estos

    sistemas se les denomina, normalmente, sistemas distribuidos).

    Tambin es posible encontrar hbridos de estos tres mtodos.

    Solo en los casos (2) y (3) es posible una verdadera ejecucin paralela de mas de un proceso. El

    termino concurrente indica paralelismo potencial. Los lenguajes de programacin concurrente

    permiten al programador expresar actividades lgicamente paralelas sin tener en cuenta su

    implementacin.

    Considerando as los procesos, queda claro que la ejecucin de un programa concurrente no es tan

    directa como la ejecucin de un programa secuencial. Los procesos deben ser creados y finalizados, as

  • 7/31/2019 Capitulo 7. Programacion concurrente

    3/9

    3

    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 sonrelevantes.

    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 len-

    guaje 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 len-

    guaje sobre algn modelo de sistema operativo.

    (3) Comienzan a aparecer estndares de sistema operativo, y por tanto los programas se

    vuelven mas portables.

  • 7/31/2019 Capitulo 7. Programacion concurrente

    4/9

    4

    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.

    7.1.1 Construcciones de programacin concurrente

    A pesar de que las construcciones de programacin concurrente varan de un lenguaje (y sistemaoperativo) a otro, deben proporcionar tres servicios fundamentales, que se citan a continuacin;

    La expresin de ejecucin concurrente mediante la nocin de proceso.

    La sincronizacin de procesos.

    La comunicacin entre procesos.

    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.

    7.2 Ejecucin concurrente.

    A pesar de que la nocin de proceso es comn a todos los lenguajes de programacin concurrente,

    hay variaciones considerables en los modelos de concurrencia que se adoptan. Estas variaciones

    conciernen a los siguientes elementos:

    Estructura

    Nivel

    Granularidad

    Inicializacin

    Finalizacin

    Representacin.

    La estructura de un proceso puede ser clasificada de la siguiente forma:

    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.

  • 7/31/2019 Capitulo 7. Programacion concurrente

    5/9

    5

    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 devida significativa. Por su parte, los programas con paralelismo de grano fino tienen un numero mayorde 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 creae 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.

  • 7/31/2019 Capitulo 7. Programacion concurrente

    6/9

    6

    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 pro-

    gramacin concurrentes es una cuestin de cierta controversia. Para una jerarqua de procesos sueleser 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.

    7.2.1 Procesos y objetos

    El paradigma de programacin orientada al objeto anima a que los constructores de sistemas (y de

    programas) consideren el artefacto en construccin como un conjunto de objetos cooperantes o, parautilizar un termino mas neutral, de entidades. Bajo este paradigma, es provechoso considerar dos tipos

    de objetos: activos y reactivos. Los objetos activos acometen acciones espontneamente (con unprocesador de por medio): hacen posible que la computacin prosiga. Los objetos reactivos, por

    contra, solo entran en accin cuando son invocados por un objeto activo. Otros paradigmas de

    programacin, como el de flujos de datos o el de redes de tiempo real, identifican agentes activos y

    datos pasivos.

    Solo las entidades activas dan lugar a acciones espontneas. Los recursos son reactivos, aunque

    pueden controlar el acceso a su estado interno (y a cualquier recurso real que controlen). Algunos

    recursos solo pueden ser usados por un nico agente en cada momento; en otros casos, las operaciones

    realizables en un determinado momento dependen de los estados actuales de los recursos. Un ejemplo

    comn del ultimo caso es el del buffer de datos, cuyos elementos no pueden ser extrados si esta vaco.

    El termino pasivo se utilizara para designar entidades reactivas que permiten un acceso completo.

    La implementacin de entidades de recurso requiere algn tipo de agente de control. Si el agente

    de control es pasivo (como un semforo), entonces se dice que el recurso esta protegido (osincronizado). Por otro lado, si se precisa de un agente activo para programar el nivel adecuado decontrol, podemos decir, en cierto sentido, que el recurso es activo. El termino servidor se utilizara para

    identificar a este ultimo tipo de entidades, y el termino recurso protegido para el tipo pasivo.

    En un lenguaje de programacin concurrente, las entidades activas se representan medianteprocesos. Las entidades pasivas pueden representarse directamente como variables de datos, o pueden

    ser encapsuladas por alguna construccin mdduio/paquete/clase que proporcione una interfaz

    procedural. Los recursos protegidos tambin pueden estar encapsulados en una construccin tipo

    modulo, y necesitar disponer de un servicio de sincronizacin de bajo nivel. Los servidores requieren

    un proceso, ya que es necesario programar el agente de control.

    Una cuestin clave para los diseadores de lenguajes es soportar o no primitivas para los recursos

    protegidos y para los servidores. Los recursos suelen implementarse eficientemente (al menos en

    sistemas uniprocesadores), ya que normalmente emplean un agente de control de bajo nivel (por

  • 7/31/2019 Capitulo 7. Programacion concurrente

    7/9

    7

    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 Representacin de procesos

    Hay tres mecanismos bsicos para representar la ejecucin concurrente; fork y join, cobegin y la

    declaracin explicita de procesos. A veces se incluyen tambin las corrutinas como mecanismo para

    expresar la ejecucin concurrente.

    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 secontinua. 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.

    7.3.2 Fork y join

    Esta sencilla aproximacin no proporciona una entidad visible de proceso, sino que aporta dos

    instrucciones. La instruccin fork (bifurca) indica que cierta rutina deber comenzar a ejecutarse

    concurrentemente con quien ha invocado fork. La instruccin join (rene) permite al que invoca

    detenerse, y por ende sincronizarse, hasta la terminacin de la rutina invocada. Por ejemplo:

  • 7/31/2019 Capitulo 7. Programacion concurrente

    8/9

    8

    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 creacinde 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 lasasignaciones 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.

    7.3.4 Declaracin explicita de procesos

    A pesar de que cobegin y fork permiten expresar la ejecucin concurrente de rutinas secuenciales,

    la estructura de un programa concurrente es mucho mas ntida si las propias rutinas son quienesestablecen su ejecucin concurrente. La declaracin explicita de procesos proporciona esta

    posibilidad.

    Otros lenguajes que soportan la declaracin explcita de procesos, como por ejemplo Ada,

    permiten tambin la creacin implcita de tareas. Todos los procesos declarados dentro de un bloque

    comienzan a ejecutarse concurrentemente al final de la parte declarativa de dicho bloque.

    En la anterior discusin se han resumido los modelos bsicos de ejecucin concurrente, y se ha

    hecho referencia a lenguajes que soportan ciertas caractersticas particulares. Con el fin de

  • 7/31/2019 Capitulo 7. Programacion concurrente

    9/9

    9

    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,