0% found this document useful (0 votes)
77 views21 pages

1 Capel

Uploaded by

Manuel dominguez
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF or read online on Scribd
0% found this document useful (0 votes)
77 views21 pages

1 Capel

Uploaded by

Manuel dominguez
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF or read online on Scribd
ny 1 INTRODUCCION A LA PROGRAMACION CONCURRENTE Indice del capitulo 1.1. Conceptos basicos y motivacién del estudio de la programacion concurrente en ia actualidad 1.2. Modelo abstracto de la programacién concurrente 1.3, Exclusion mutua y sincronizacion 1.4. Mecanismos de sincronizacién de bajo nivel en memoria compartida 1.5. Propiedades de los sistemas concurrentes 1.6. Logica de programas de Hoare y verificacién de programas concurrentes 1.7. Ejercicios 2 PROGRAMACION CONCURRENTE Y EN TIEMPO REAL 1.1, Conceptos basicos y motivacién del estudio de la programacién concurrente en fa actualidad Si un programa secvencial es un conjunto de declaraciones de datos ¢ instrocciones que se éjecutan siguiendo una sola secuencia, entonces podemos entender un programa con- carrente como aquel codigo en un lenguaje de programacién de alto nivel que especifi- que 2.0 mis unidades de ejecucién independientes, que deno:ninaremos procesos, cope rando en la realizacién de una determinada tarea que es importante para avanzar en Ja tealizacién de los calculos de dicho programa y que constituyen su principal cometido. El concepto de proceso ha de ser entendido, por consiguiente, como wna entidad software abstracta, dindmica, activa, que ejecuta sus instrucciones y alcanza diferentes estados', Hay que tener presente que solo el conjunto de instrucciones de un programa no puede considerarse un proceso, por este motivo resulta engafiosa la definicién de proceso concurtente como un progrania seovencial en gecucién que algunos textos antiguos de sistemas operativos solian realizar. Pasa que el procesador de nuestro ordenador ob- tenga toda la informacién relevante asociada a un proceso, en cada momento de sv cje- cucién, es necesatio también que conozca la informacién asociada a su estado, es decit, ‘un proceso no es “inicamente la ejecucién independiente de una secuencia de instraccio~ nes, sino ademés inchuye el estado del mismo y su capacidad de interaccién con el en- tomo del programa en cada momento. Desde un punto de vista general, en el estado de tun proceso se integra una serie de valores que lo definen de manera concreta, en cada instante de su ejecucién, dentro del programa o de la aplicacién sofeware y que se en- cuentran ubicados en determinados registros del procesador y en las memorias del sistema. Por consigniente, se han de conocer los valores de los registros del procesador que co- sxespondetin con el contador de programa (pc), estados de la pila (sp) y de la memoria acumulativa (heap) para cada proceso del programa, asi como los datos de acceso a dis~ positivos que esté utilizando durante sa ejecucién, a los archivos y cualesquiera otros recursos de los que dicho proceso es pmpietario y que protege de un acceso competitivo e incontrolado por parte de los otros procesos concurrentes del programa. Desde el punto de vista del sistema operativo, un proceso se caracteriza por una zona de memoria estructarada en varias secciones (Figura 1.1), que inchaye la secuencia de instrucciones que esté ejecutando, el espacio de datos de tamaiio fijo ocupado por variables globales o astaticas, la pila que representa un espacio de tamnafio vatiable ocupado por variables /ara/er a procedimientos y sus patémetros, asi como wna memoria dindrnica © heap, como suele denominarse al espacio ocupado por variables no estiticas, es decic, normalmente asociadas a variables dindmicas que son creadas, asignadas y destruidas antes de la terminacién del proceso o del propio programa. * Por ahora, entenderemos el concepto de estada del pragrama come el conjumto 8e valores de watiables siheey no visi- bles: contador de programa (pc), punter del pile (gp) en cada instante diferenciado de su ejecucién. INTRODUCCION A LA PROGRAMACION CONCURRENTE 3 ? Proceso Figura 1.1. Modelo de proceso concurrente En un programa concurrente pueden existir muchas secuencias de ejecucién de instruc- « ciones con, al menos, un flujo o filo de control de ejecucion independiente por cada uno: | de los procesos que conforman el pragrama. Sits plataforma de ejecucién sobre la que finalmente se despliega el cddigo de sues- tro programa posee menos mica: 0 wnidades de procesamiento independientes que el ntimero de los procesos creados en tal programa, los multiples flujos de control inde- pendientes se entremezclan y formarin una secuencia de ejecucién por cada niicleo del procesador. Esto lo podemos entender como un modelo de ejecucién concurente de las instracciones con una caracteristica fundamental: preserva las propiedades de parale- lismo légico del programa, independientemente del nimero de procesadores que real- mente ejecuten concursentemente el codigo. De esta forma, un programa concurrente siempre ser més eficiente que un programa secuencial, ya que, entre otras cosas, permite el avance de varios hilos de control légico en Ja ejecucién global de las instrucciones, acceso a memoria, gestion de comunicaciones y dispositivas; evitindose, por tanto, que determinados ptocesos que realizan frecuentes operaciones de entrada y salida puedan, limitar la velocidad de ejecucisn de ottos procesos més orientados a los célculos, En general, la existencia de procesos concutrentes en los programas hace que no se produz- can suspensiones indeseadas en Ja secuencia de ejecucién de inserucciones en los micleos del procesador, que podrian seguir avanzando mientras los procesos ligados a Ia trans- ferencia de informacion estin esperando datos del entomo del programa. «En programas con procesos destinatios a interaccionar con su entorno: entradas/salidas ‘ frecuentes, recepcion de mensajes, excepciones, tratamiento de sefiales, etc., el aprove- ‘ chamiento del tiempo del procesador que se consigue con un programa concurrente es * mucho mejor que con uno secvencial equivalentte, es decir, programado para realizar la | misma tarea 0 conseguir los mismos resultados, pero con solo una linea de flujo de ejecu- 4 PROGRAMACION CONCURRENTE Y EN TIEMPO REAL ? Un programa concusrente es la base del disefio de cualquier simulacién potque el paradigma concurrente siempre modelatd mejor a los sistemas seales que cualquier pro- grama secuencial, ya que los sistemas fisicos suelen estar compuestos de varias activida- des que se ¢jecutan en paralelo y cada una de ellas admite ser simmulada de fotma mucho més natural mediante un proceso concurrente independiente, es decir, un programa con- curtente est4 mas cerca de los modelos multidimensionalss teales que uno disefiado, basén- dose en una visiin unidimensional del mundo que \e todea, realizando un ciclo secuencial de sondeos periddicos de sefiales o mensajes enviados desde el exterior del programa. En consecuencia, los tétminos concurentes, coneurrendia, etc., que utilizaremos de ahora en adelante pata describir el potencial de ejecucién paralela que pose un programa escrito en uno de los lenguajes de programacién actuales significan el potencial de para- ‘elismo que poseen determinadas unidades de cédigo de un algoritmo, aplicacién o sis- tema desde un punto de vista Mgico e independiente del mimero de procesadores u otras caracteristicas del hardware del sistema. "De acuerdo con la afirmacién anterior, podemos definir la programacién concurrente : * como el conjunto de notaciones y técnicas de programacién utiizadas para expresar el : paralelismo potencial de los programas y, consecuentemente, pasa poder resolver los * problemas de sincronizacién y comunicacién que se presentan durante la ejecucion de : los procesos. 1.2. Modelo abstracto de programaci6n concurrente La progeamacién concurrente no es solo un panadigna o modelo de los lenguajes de pro- gramacién, sino que es, sobre todo, un madelo abstracto de computacién que sitve para expre- sar en un nivel de abstraccidn adecuado” el paralelismo potencial de tos progeamas de ordenador, independientemente de la implementacién de paralelismo en el nivel arqui- tecténico del sistema de computacién utilizado. Los buenos lenguajes y notaciones consirrenies deben proporcionar primitivas de programacién utiles para resolver problemas de sincronizaciéa y comunicacién entre procesos concurrentes que puedan utilizarse, de forma general, en diferentes axquitectu- zag de computadores, pero... jesto es un ideal! El modelo abstracto de Conourrncia que vamos a introducir consigne, sin embargo, avanzar mucho hacia la consecucién de este objetivo maximal, ya que nos permite disponer de una serie de herramientas que nos ayudan en la labor de conceptualizacién y disefio de los programas concutrentes, tales como el poder razonat la solucin de los problemas que se nos planteen, al nivel de detalle adecuado, sin entrar en consideraciones de demasiado 2 Un nivel de abstraccin que nos permita resolves problemas que sean de nuestro interés en el campo dela Concur, sin atascarog en los detalles de implementaci6n del paralelismn0 a nivel del microprocesador. INTRODUCCION A LA PROGRAMACION CONCURRENTE 5 Jujo nivel que nos impidan obtener soluciones a los problemas de comunicacién entre ocesos de uns forma sencilla; si como el facilitar la notacion de progsamacion. que fi- Bente utilicemos, ye que propicia la definicién de lenguajes de programaciéa, que in- tuyen ls instrucciones de comunicacién y sincronizacion abstraetas, sin tener que recurrit f liamadas sl sistema, 0 instrucciones de nivel maquina, pata resolver los problemas que ‘nos interesan, ademés los programas que desarrollemos serin, transportables ya que son in- dependientes de una miquina o plataforma de ¢jecucién concreta, solo con disponet de ‘un compilador adecuado a nuestra plataforma del lenguaje de progtamacién concurrente. El modelo absteacto de programacién concurrente se define a partir de $ hipétesis, ‘9 axiamas si lo consideramos como un sistema légica formal de base matematica para ra- zonar sobre la correccidn de los programas: 4, Atomicidad y entrelazamiento de las insteueciones. 2, Coberencia en el acceso concurrente a los datos del programa. 3. _Impetibilidad de la secuencia de instrucciones atémicas 4. Independencia de la velocidad relativa de ejecucién de los procesos. 5. Progreto de todos los procesos en tiempo finito, 1.2.1. Atomicidad y entrelazamiento de las instrucciones atémicas de los procesos A partic de un programa concurrente escrito en un lenguaje de alto nivel siempre se puede llegar a un conjunto de instrucciones equivalentes generadas en el nivel més bisico posible, tal como se muestra ent la Figura 1.2. Dicho nivel de insteucciones se corresponde, normalmente, con el repertorio de instrucciones a nivel maquina 0 ensamblador de los sistemas de computacién. Tiene la propiedad de que cada una de sus instrucciones se ejecuta sin que pueda ser detenida por un cambio de contexto o cualquier otra interrupcién del sistemna, es decir, las ins- teucciones se ejecutan de una forma indivisible o afémiva. Una consecuencia practica de esto consiste en que el tipo de ejecucion de los procesos de un programa concutrente, ; tanto si utilizan paralelismo rea? para iniciar la ejecucion de sus instrucciones como si ¢s paralelismo ligice, no influité en los resultados del programa, solo en la rapidez con que estos se obtengan. Segiin la interpretacin anterior, la Figura 1.2 muestra una parte de las secuencias de instrucciones que podria generar un programa P que programsara 2 procesos concurrentes P; y P; cuyas secuencias de instrucciones atémicas representaremos como > Paralesmo seal significa ejecucin simultines de insteucciones por un procesador 0 nico diferente de miceapeace- 6 PROGRAMACION CONCURRENTE Y EN TIEMPO REAL ? {J12} e {Idx respectivamente. El conjunto de todas las secuencias posibles de entrelaza- miento de las instrucciones atémicas de los procesos Pl y P2 se define como el comporta- -miento observable del programa P, Es decir, la ejecucién de P puede ser una cualquiera de estas secuencias que definen su «importamiento’, pero no podemos saber cul se producita finalmente cada vez ni tampoco influis para que sea una de ellas la que se produzca en particular, Esta caractetistica fundamental se suele denominat 1a determinismo de la ejecu- cién de los programas concurrentes. AL Pp Secuencias posibles Ti Ta q Fu Ia Ta Tn Fn Is Tan ta In In te In Ten Les hs Ia Figura 1.2. Secuencias de entrelazamiento de instrucciones atémicas de 2 procesos La anterior intexpretaci6n de la ejecucién de los programas concuzrentes es un mo- delo de paralelismo independiente de Ja arquitectura conceeta que posea la plataforma sobre la que finalmente se ejecute el codigo de wa programa. 1.2.2, Coherencia en el acceso concurrente a los datos La ejecuciéa concurrente de 2 instrucciones atémicas que acceden a una misma direc- cién en memoria ha de producir los mismos resultados tanto si ambas instrucciones se gjecutan con un paralelismo real, o se suponga paralelismo légico en la ejecucién de ambas, es decir, que se ejecuten secuencialmente, una después de otta, pero en un orden arbitrario e impredecible. La propiedad de coherencia en el acceso a los datos establece que, al terminar de acceder a estos, los procesos han de dejar la representacién en me- moria de tales datos en un estado coherente con el tipo al que pertenecen. En la Fi- guia 13 se puede ver que el resultado pode ser igual al valor 1 0 2 (no podemos saber cadl), pero dicho valor es consistente con los que puede tomar la variable que modifican los 2 procesos, segtin las definiciones de datos y declaraciones de variables zealizadas en el programa. “El conjunto de todas las secuencias de entrelazamicnto de instraccianes atomicas que se generan a parts del eédigo de Jog procesos del programa. INTRODUCCION A LA PROGRAMACION CONCURRENTE 7 En la Figura 1.3, dado que las instrucciones J; ¢ Jz acceden, una después de otra, a la posiciGn de memoria del registro acumulador del procesador, el valor final en la-varia- ble xno esti inicialmente determinado, pero coincidira con el iltimo valor asignado, ya gue x es asignada 2 veces por procesos distintos durante la ejecucién del cédigo en un orden impredecible. Si, por el contrario, I; ¢ J; accediesen simulténeamente a la posicién de memoria de la variable compartida, se podria producir mezcla de patrones de datos y el contenido final de x podria llegar a ser un valor espurio. BR B Secuencias de en} lazamiento Licstore x, > Tuicstore x, 2> Tei Lir (2) ven) Figura 1.3. Secuencializacién de la ejecucién de los procesos concurrentes en el acceso a variables compartidas por el orden que impone el controlador de memoria del hardware La suposicién que establece esta hipdtesis del modelo abstracto esta soportada por el hardware de control de acceso a memoria de los sistemas reales. Por consiguiente, la coherencia de los datos de las variables, tras un acceso concurrente a una misma direc- cién, es asegurada por el controlador de memoria de los computadores. 1.2.3. Irrepetibilidad de la secuencia de instrucciones atomicas El miimero de secuencias de entrelazamiento de instrucciones atémicas que se puedan llegar a formar a partir de un programa resulta ser inabarcable. Por tanto, es bastante improbable que dos secuencias de ejecucién seguidas de un programa concutrente pue- dan repetit la misma sucesién de instrucciones atémicas. Este hecho hace muy dificil la depuracién y andlisis de correccién de los programas concurrentes y, en consecuencia, se originan una clase de exrores iransitorios que son muy dificiles de identificar y corregit en el cédigo de los programas, es decir, se trata de errores que aparecen en unas secuen- cias de ejecucién del programa y en otras no. Por consiguiente, se necesita una bala de plata para conjurar la tendencia a la apanicidn de exrores transitorios ocultos en los pro- gramas cuando se desazrolla software de aplicaciones concurrentes. Como veremos mas adelante, es necesario utilizar métodos formales, con el rigor de la Légica Matematica, para verificar Ia correccidn de los programas concurrentes, asi como poder identificar y climinar los mencionados estores transitorios que subrepticiamente pudieran aparecer al ejecutar tales programas. 8 PROGRAMACION CONCURRENTE Y EN TIEMPO REAL “ 1.2.4. Velocidad de ejecucién de los procesos La correccid de los programas concurrentes no puede depender de la velocidad de cjecucidn telativa de unos procesos con respecto a otros. Si no se cumpliese este requi- sito, se producitian Jas signientes anomalias durante la ejecacin de fos procesos de un programa concustente en las distintas platafosmas de computacién: 1. Falta de transportabilidad, si se hicieran suposiciones acerca de la velocidad de eje~ cucién de los procesos para legat a obtener los resultados esperados del pro- gxama, los programas concutrentes dejarian de ser transportables entre distintas plataformas, ya que, al cjecatar su cédigo en otra, con procesadores de caracte- risticas muy diferentes, posiblemente no mantendsian su cosrecto funciona: miento. 2. Aparicion de condiciones de carrera, que producitian resultados erréneos al acceder los procesos concurrentemente a variables o secciones de cédigo compartidas entre ellos. Si la correccién de un programa dependiera de la velocidad de eje- cucién de sus procesos, se producisian innumerables exrores transitotios en las sjecuciones del progsama sin mas que modifiear un poco las condiciones de contexte de los procesos. En la Figura 1.4 se puede ver un ejemplo simple de aarera en acreso a datos entee 2 procesos en la asignacién de la variable datas (inicialmente = 0) pot parte de los procesos Py y Pz. La variable aludida puede terminar con el valor: +1, 0, I y no hay forma de predecitlo, su valor final dependerd de la velocidad y el orden en que los procesos acce- dan a las variables de este seymento de cédigo. Si alguno de estos resultados no fuese correcto con fespecto a la especificacion inicial de las propiedades del programa en el que se hubieran programado los 2 procesos, diremos que establece una condicion de carrera entre tales procesos. Process Pir Process 2) ar = datost Br = datos: pearis seb 1; datos: = a datos: = b; Figura 1.4. Ejemplo de condicién de carrera entre dos procesos No obstante, hay una excepcién en ef cumplimiento de esta hipétesis del modelo abstracto, ya que existe un tipo de programas, que normalmente poseen un alto grado de concurtencia, en Jos que si se establecen restricciones respecto al tiempo y del orden de ejecucién de detetminados procesos, lo que afecta a las velocidades de ejecucién re- lativas entre estos. En las aplicaciones consideradas de tiempo real se asignan distintos niveles de prioridad a los procesos, que son seleccionados con distinto privilegio para acceder al procesadot en ¢] transcurso de la ejecucién de la aplicacion a la que pertene- cen, estos son los programas que se utilizan para desarrollar sistemas de tiempo real. INTRODUCCION A LA PROGRAMACION CONCURRENTE 9 Por iltimo, dentro del modelo abstracto, se ha de asumir que se cumple la hipétesis de progreso finito que también esté relacionada con la velocidad de ejecucién de los procesos de un programa concurrente. Sin esta hipétesis, no se podiia asegurar nada robre la satisfaccion de las propiedades de cosrecci6n, ya que el cumplimiento de dichas propiedades dependeria dela plataforma concreta donc se pudiera ejecutar el programs. Por ejemplo, propiedades como la de vivacidad de los procesos no podrian Ilegar a de- mostrarse si no garantizamos que la correccién mantiene su independencia de las velo- cidades de ejecucién de los procesos. 1.2.5. Progreso de los procesos en tiempo finito Para que podamos verificar la correccién de los programas concurrentes, todos sus pro- cesos han de conseguir eecutarse y, por tanto, avanzar siempre en los célculos para los que fueron programados. Esto se puede entender a dos niveles, que son necesatios para comprender el avance en la ejecucién real de un programa: 2) Globalmente, si existe al menos 1 proceso preparado para ejecutarse, es decis, se puede demostrar que, si el programa no ha entrado en una situacién de inter- bloqueo, entonces eventualmente’ se permitird la ejecucién de agin proceso del programa. b) Lovalmente, todo proceso que comienza \a ejecucién de una seccién de su cédigo eventualmente ba de legar a completar la ejecucién de esta secciéa. Resumiendo, podemos decir que la hipétesis del progreso finito se puede definir mediante la siguiente afirmacién: no puede existir en absoluto ninguna configuracién aceptable de un programa a lo largo de la secuencia de estados de una de sus ttazas, 0 condicién satisfecha por el estado oculto del programa en cualguier momento, en el que un proceso podria detener arbitrariamente su ¢jecucién durante un tiempo no definido en el tiempo de ejecucién del pro- grama concurrente en el que ese proceso fue declarado. 1.2.6. Consideraciones sobre el hardware Atendiendo a su arquitectura de computadores, los sistemas informéticos actualmente implementan la concurrencia segtin tres modelos generales, que podtian también pre- sentar hibridacién entre ellos, como se puede ver en la Figura 1.5. dct, en algiin momento futuro que no se puede posponer durante mucho tiempo 10 PROGRAMACION CONCURRENTE Y EN TIEMPO REAL Red de Comunicacién St — “Ea be] [nor ile” | [Memoria] (Memorial [Mero {Memoria} fe) Figura 1.8. Arquitecturas de sistemas con diferenites grados de paralelismo: (a) procesador multiicleo; (b) multiprocesador; (c) mutticomputador Los modelos generales representan a los sistemas atendiendo al niimero de proce~ sadores y a su distribucidn, segtin las siguientes categorias de sistemas: a) Procesador multinicho: en este tipo de arquitectura suelen existic muchos més pro- cesos que muicdeas (unidades fisicas de ejecucién independientes) y se ha de mo- delar el paralelismo mediante el entrelazamiento de multiples hilos de ejecucién, este modelo lo podemos entender como una categoria de sistemas en los que la concurrencia en la ejecucida de los procesos se puede conseguir con o sin pa- ralelismo real. b) Mutiprocesadores: en este caso siempre existe paralelismo seal y este tipo de mul- tiprocesador notmalmente se ha disefiado para ser programado con lenguajes 0 bibliotecas con instrucciones que se traducen a érdenes patalelas, es decir, el cédigo de los programas ejecutard simultineamente varias instrucciones elemen- rales en procesadores diferentes y existird una memotia comin a través de la cual se pueden comunicar los procesos. ©) Multicomputadores: son multiprocesadores distribuidos en los que cada procesa- dor o unidad fisica de ejecucién posee una memoria independiente y no com- partida con otros, de manera que para poder comunicar procesos ubicados ea INTRODUCCION A LA PROGRAMACION CONCURRENTE 14 diferentes procesadores es necesario utilizar una red o una interconexidn de alta velocidad que permita conseguir un alto nivel escalado‘y suelen poseer una pro- gramacién més complicada que ninguno de los sistemas anteriormente introdu- cidos. Se dice que existe paralelismo real cuando los programas concurrentes se ejecutan en un sistema de la categoria descrita anteriormente como multiprocesador 0 raulticompu- tador. Si se dispone solo de un sistema que proporciona un ntimero de procesadozes inferior al de procesos de la aplicacién, entonces se dice que existe pseudoparalelismo. Sin embargo, desde un punto de vista conceptual y gracias al modelo abstracto de la progra~ macida concuttente, nuestros algoritmos y programas tendrin definido un comportamiento que los define univocamente independientemente del tipo de paralelismo que posea la plataforma de ejecucién donde finalmente se desplieguen. Podemos afirmar, suponiendo que nuestros lenguajes y bibliotecas de programacién siguen el modelo abstracto ante- rior, que el tipo de paralelismo afectaré al rendimiento (velocidad de ejecucién, etc.) del cédigo durante su ejecucién, pero no a la correcci6n de los algoritmos o programas que disefiemos. De hecho, actualmente existen lenguajes de programacién concurrente, que se han definido como neuires respecto a los diferentes tipos de arquitecturas, permitiendo transportar los programas entre plataformas de ejecucién de una forma totalmente trans- patente pata el programador, que no necesitari conocer los detalles o el conjunto de instracciones propias de ninguna plataforma. 1.3. Exclusion mutua y sincronizacion La exclusién mutua asegura que una serie de sentencias del texto de un proceso, compar- tidas con otros procesos del programa, se ejecutardn de una forma indivisible, es decir, no se permitird que més de un proceso del programa ejecute un bloque de estas senten- cias concutrentemente’.Dicho bloque (0 seccién) de sentencias dentro del texto de un proceso se denomina secxién ont. Con las primitivas de programacién de un lenguaje adecuadas, si 2 0 més procesos intentan ejecutar una seccién critica, solo lo conseguiré uno al tiempo; los demas han de esperar hasta que dicho proceso acabe y entonces lo vuelven a intentar. Un ejemplo de acceso en exclusién mutua es la asignacién de recursos (respaldo de archivos, plotters, impresoras, etc.) que realiza, por ejemplo, un sistema operativo a los distintos procesos de usuatio; ya que, si mezclaran los trabajos enviados pot estos, la salida que produciria el dispositive compartido por los procesos de usuario serfa inaprovechable. La estructura que suele tener el cédigo de un proceso que incluye una secciéa critica es la siguiente: « Integra de muchas nuevas unidades/procesadoces segtin la potencia de céleulo nccesasa pasa ejecutar un algo- ritmo, sin perder zendimiento, 7 Podeia no coincidir con un Bloque del prograer, sein se entiende en la mayoria de lengusjes de programacién. 12 PROGRAMACION CONCURRENTE Y EN TIEMPO REAL Resto de operaciones fuera de la seccién critica; Protocolo de adquisicién; Protocolo de restitucién; Los protocolos de adquisicin y restitucién son bloques de instrucciones cuyo ob- jetivo en conjunto es conseguir que se cumpla la condicién de exclusién mutua en el acceso de un proceso a una seccién critica que tiene programada en su texto. El primer protocolo o de adquisicién decide, en el caso de que haya competencia entre varios pro- cesos, cual de ellos entra en seccién critica en cada iteracién; al resto no se les permite avanzat y entrat 2 ejecutar el bloque de sentencias hasta que termine de ejecutarlas el proceso que entté primero. El protocolo de restitucién sisve para permitir 2 un nuevo proceso (que posiblemente se quedé espetando tesminar el protocolo de adquisicién) entrar después en la secciéa etitica 1.3.1. Sincronizaci6n En los programas concurrentes los procesos tienen necesidad de comunicarse durante su ejecucién pata cooperar en la realizacién de una tarea comtin, Como antes se ha dis- cutido, la comunicacién entre los procesos se puede realizar mediante variables compar- tidas 0 mensajes, dependiendo del tipo de paralelismo gue oftezca la plataforma sobre la que se ejecute el progeama concurrente. Tal comunicacién entre procesos da lugar a Ia necesidad de que exista una sincconizacion entre ellos durante el transcurso de sus ejecuciones. Existen dos escenarios fundamentales de sincronizacién entre los procesos: a) Sineronizacion con condiciones: consiste en. detenet la ejecucién de un proceso hasta que se cumpla una determinada condicién. Esto significa, en un nivel més cer- cano al sistema, no permitir que el proceso cambie su estado, es decir, ejecutar Ja siguiente insteuccién de su texto, hasta que se cumpla la condicidn, que suele evaluarse a partit de los valores de las vatiables del programma, lo que también se lama sincronizar el proceso con la condicién. b) Exclusin mutua: se puede considerar como una condicién de sincronizacién par- ticular, pero muy importante porque se da a menudo cuando un proceso no puede avanzar hasta que una seccién critica quede libre y se le autorice a entrar en ella, lo cual es una condicién de sincronizacion especifica. La programacién de bifer circular de capacidad limitada de la Figuta 1.6 es un ejemplo tipico que ayuda a entender la diferencia entre las 2 formas de sincronizacién, intzoducidas anteriormente y que son comunes entre los procesos de un programa con- currente. INTRODUCCION A LA PROGRAMACION CONCURRENTE 13, Al biifer circular acceden procesos productores para insertar datos y procesos con- sumidores para retirarlos. El objetivo de la estructura de datos denominada biifer es la de desacoplar la ejecucién de procesos de tipo consumidor de los de tipo productor, permitiendo que cada uno de estos procesos se ejecute de forma independiente sin preo- cuparse que el bifer se pueda desbordar o que se intente obtener datos de él cuando esta vacio. Considérese, por ejemplo, el escenario que se obtendrfa s inicialmente se ejecutan una tanda de productores y todavia no hay ningiin proceso preparado para que pueda consumir los datos producidos, entonces los datos se guardarin temporalmente en el afer a la espera de ser retirados por los procesos consumidores cuando alguno de estos se ejecute. Ademas, en este ejemplo de la implementacién del biifer circular, la condicién de sincronizacion entre ambos tipos de procesos, que hemos denominado exclusién mutua, se esté utilizando para asegurar que ua proceso productos y otro consumidor no accedan al biifer al mismo tiempo y, por tanto, se pueda producir una condicién de carrera, que pudiera producit errores transitorios, en el acceso concurrente a un mismo elemento de este bitfer por varios procesos* La sincronizacién con condiciones en ambos tipos de procesos se utilizaré para asegurar que un mensaje introducido en el biifer no sea sobrescrito antes de ser extraido, o bien pata evitar la inseccion de datos en un biifer lleno; 0 un intento de extraccién de un bifer vacio, errores transitorios que aparecerian en un escenario de ejecucién de los procesos en el que se intenta consumir 2 veces después de haber producido e insertado tun solo elemento en un biifer vacio, tal como muestra la secuencia etiquetada como ddlegal» en la Figura 1.6. an sin ve recone Pogrea tot ltr 8 3 j tenons (este scupedor nedNsi Pega soon |_tr nlm oie oa co gootat vo1on ! cot rang wtot09 (wicrelom_ecupadersr0} Conctenacionesde operaciones read ite: tp ste, pred eter, con_reaa. conde, pod ste. § 2) fpr}. wrte, conse, con2.read2.1 > secvenciade ajecuién egait De Wegund letra sobre clda no esr ain Figura 1. . Representacién del bifer circular en el modelo concurrente denominado productor-consumidor ® Si se diem tal condicién de carrera entee procesos con un bifer que contuviceselenientos complejos, se pode llegar a lece de béfer un mensaje paseakmente escrito 44. PROGRAMACION CONCURRENTE Y EN TIEMPO REAL ? Desde el punto de vista del modelo abstracto de la programacién concutrente, el papel de la sincronizacién consiste en restringir el conjunto de todas las posibles secuen- cias de ejecucién de un programa concurrente a solo aquellas secuencias que pueden considesarse correctas desde el punto de vista de las propiedades concurrentes que ha de cumplir dicho programa. 1.3.2. Creacién de procesos Las ptimeras notaciones, que se incluyeron en lenguajes imperatives para expresar la ejecucién de procesos concusrentes en un programa, no posefan primitivas independien- tes de creacién de los procesos y de sincronizacin, sino que la propia operacién de creacin de procesos sincronizaba implicitamente al programa donde se creaban Jos pro cesos con la terminacién de estos. Los lenguajes y sistemas modernos con facilidades para la programacién concurrente sepatan ambos conceptos ¢ imponen una estructura al programa y a sus procesos. La primera idea pata sepatar la creacidn de procesos fue la introduccién de una primitiva de declaracion de procesos como un bloque del programa: De modo que los programas declaran explicitamente rutinas que se van a ejecutar concutrentemente y les péimitivas para la programacién de mecanismos de sincronizacién entre procesos apare- cen también explcicamente como otras instrucciones més en el cddigo de los programas. La declaracién de los procesos, atendiendo a la duracién de estos durante el tiempo de ejecucién de un programa, puede ser: a) Estétiee. cuando se declara un niimero fijo de procesos que se activan, cuando se injcia la ejecucién del programa al que pertenecen. b) Dinamica. si se especifica un niimero variable de procesos que se activan en cual- quier momento durante la ejecucién, ademas con esta modalidad se pueden eli- minar procesos que ya 0 interesan durante la ejecucidn del programa para aho- na memoria y ottos recursos. Bjemplos de lenguajes de programacién que poscen alguno de los tipos de declara- cién de procesos son: MPI [Snit90} que utiliza la definicién de grupos de procesos co- nectados en cada sesién?. El lenguaje Occamn [INMOS84] para progtamaci6n de ¢ranipa- zers, Pascal Concurtente [Brinch-Hazsen75}, Modula [Wirth85}. Mas recientemente, el lenguaje de mayor difusién que incluye creacién dindmica de procesos es Ada [Bar- nes94]. ° Cada cominicator en MPI proporciona a cada proceso del grupo declarado un identifcadoc independiente que Io ‘ddentifiea dentro de una topologia de conexién ordenada. INTRODUCCION A LA PROGRAMACION CONCURRENTE 15 Creacién de procesos mediante ramificacion fs una forma no estructurada de cteacién de procesos que utilizan los sistemas opera- s UNIX y sus variantes, que se utiliza con dos instrucciones basicas: fork () y tivo: join ()- La insteuccibn fork () tamifica el flujo de control del programa o proceso que hace Ia llamada iniciando la ejecucién de una funcién que nombea y que comenzard a ejecu- terse como un proceso concurrente independiente que entrelaza sus instrucciones con Jas del programa principal. En la Figura 1.7 puede verse que la llamada a fork () produce tuna segunda copia del programa (P) totalmente independiente del proceso (P) que te- presentala ejecucién del programa que realiza la lamada, que continuasé ejecutindose. pide fork: ippid <0 fark error Jelseif (ppd = 1) Ps else a Figura 1.7. Representacion del resultado de la ejecucién de una operacién fork () en UNIX La instruccién de unién de lineas de control independientes join() ejecutada en el texto de un proceso P permite a este esperar a que otro proceso P” termine su ejecu- cién, antes de proseguit con la siguiente instruccién. P es el proceso que invoca la ope- sacién de unién de flujos de control y P” el proceso objetivo. Al finalizar la lamada a 16 PROGRAMACION CONCURRENTE Y EN TIEMPO REAL ? join ()se puede estar seguro que el proceso objetivo ha terminado con seguridad, La ventaja que tiene utilizar el mecanismo fork/join, que inchuye la ramificaci6n de fa linea de control principal y una espera posterior, frente a programar un bucle de espera ocu- pada en el texto del proceso P hasta que P’ haya terminado, consiste en que el proceso que hace Ia llamada a la insteuccién join() se suspenderd y no consumir’ ciclos del procesador hasta que el proceso P’ haya tetminada y se wetinan con df, a diferencia de lo que ocurte si se realizase dicha espera ocupada. La seméntica de la operacién join () establece que sea Ja operacién nula, por tanto no hay cambios de contexto y se evitan innecesarios ciclos del procesador, si al realizar el proceso P la llamada a la operacion join (), el proceso objetivo P’ hubiera terminado ya. La ejecucién, por tanto, de dicha operaciéa no produce ningtin efecto en el estado del programa en este caso. Las principales ventajas de la creacién de procesos mediante ramificacién frente a otros mecanismos consisten en que esta forma es prictica y potente, permitiendo una creacién dinaimica, no estructurada y muy flexible de procesos concurrentes. Los incon- venientes més importantes son que induce falta de esttucturacidn en los programas; ya que, al poder aparecer en bucles, condicionales, fusciones recursivas, ete. hace muy di- ficil comprender su funcionamiento, lo que implica dificultades serias para su depuracion y posterior verificacion. Creacion estructurada de procesos El par de insteucciones (cobegin, coend) de creacién de procesos que poseen algunos Ienguajes concurrentes se considera una sentencia estructurada porque tiene un punto de comienzo, dado pot cobegin, que inicia la ejecucién concusrente de las insteucciones, fanciones, procesos, etc. que aparecen a continuacién y un punto de finalizacién que supone la terminacién de todas las instrucciones del bloque antes de ejecutarse la ins- truccién coend: cobegin S17 Sei m7 Spcoend La instrucciés siguiente al coend, en el fragmento de programa anterior, solo se cjecutaci cuando tedas las sentencias componentes 5; 5; ...3 Se que enteelazan sus ins- teucciones en un orden no determinado, hayan terminado, El bloque que representa el conjunto de seatencias posee un tnico punto de teeminacién, que teline las distintas lineas de control creadas en una sola, la que existia antes de ejecutarse la insteuccin cobegin. El bloque de programa donde aparece la construccién anterior depende de la teminacién de las sentencias para completar su ejecucién dentro del programa al que pertenece. Consecuentemente, el texto entre ambas instrucciones se puede considerar un bloque del programa, con una sola entrada y una salida, contribuyendo a mantener la estructura del programa: INTRODUCCION A 2A PROGRAMACION CONCURRENTE 17, Creacién de hilos POSIX Laindependencia que existe entre las zonas de memotia propia de los procesos en UNIX proporciona proteccién implicta en al acceso a variables del programa, pero no es muy flexible si necesitamos utilizarlo para definir mecanismos de sincronizaciéa en interac- ciones cooperativas entre procesos, ya que presenta Jos siguientes inconvenientes: a) Elcoste de tiempo y uso de recursos necesario para levar a cabo el cambio de contexto entre miltiples procesos UNIX es elevado. b)_ Elplanificador del sistema solo puede gestionar eficientemente hasta un néimero determinado de procesos. ©) Las operaciones del sistema asociadas a este tipo de creacién de procesos, para usar variables de sincronizacién compartidas (cerrojos, semxiforos, etc.) suelen set demasiado lentas. d) Ademés, la sentencia fork() es un mecanismo de cteacién de procesos no- estructurado, que suele propiciar ertores en la programacién dado que, a veces, no se sabe bien qué instancia o realizacién del proceso original se esta ejecu- tando en cada momento". Una posible soluciéa seria renunciar a la proteccién detivada de tener espacios de di- recciones sepatados, que se presupone si se programa directamente con Jos procesos de UNIX. Esto nos lleva al concepto de hilo de contolindependiente dentro dle un proceso como entidad de planificacién. Los sistemas operativos conformes con POSIX 1003.1e —como Linux— ahora planifican procesos e hilos, ver Figura 1.8. Un proceso puede contener ahora ‘uno o varios hilos. Por tanto, podemos entender a un hilo como un flujo de control que comparte con otros bilos el texto del proceso al que pertenecen. Cada hilo tiene su propia pila, vacia al inicio, donde almacena sus vatiables locales y comparte con otros hilos la zona de datos donde se almacenan las variables globales y el heap del proceso al que pertenecen. Funcién de creacion de hilos POSIX Cada proceso tiene asociado un texto 0 programa que al principio existe como un solo hilo que ejecuta la funcién main () (en C/C++). Conforme avanza la ejecucién del pro- grama, ¢! hilo que inicialmente ejecuta dicha funcién main) podria crear 1 0 mas hilos asociados a su mismo proceso, Un hilo que crea a otro designa una funcién £() para que este lo ejecute, continuando con su propia ejecucién después de iniciarse el nuevo hilo que ejecutara las instrucciones de la funcidn #{) concurrentemente con las del resto de los hilos del programa hasta que él mismo acabe o bien se de alguna de las condiciones de terminaci6n de hilo previstas en Ia especificacién POSIX. La funcién que crea y activa un nuevo hilo, utilizando la interfaz POSIX 1003.1¢, es la siguiente: ° aca distinguit las instancias de un mismo proceso, la funciéa Fork () devuelve el valor 0 sil cédigo que se ejecuta «en ese instante es el del proceso pade (el que inicié le zamiicucién de los procesos hij). a ——— - 18 PROGRAMACION CONCURRENTE Y EN TIEMPO REAL ? int ptht_ereate (pthread t *nueva_hilo, const pthread_attr_t*atr, void* (*nanbre_funcion) (*void), void*args) Procesos UNIK Nivet de "recursos dda ba nivel del sistema Hilo D: PTHREAD_SCOPE_SYSTEM Resto deritos: PTHREAD_SCOPE_PROCESS, Figura 1.8. Representacién de la planificacién de hilos POSIX 1003.1c (thread package) Los pardimettos de la fancidn anterior, en orden de aparicién de izquierda a derecha, son los siguientes: a) pthzead_t: es un tipo opaco que actéa como un manejador 0 handle del nuevo hilo, es decir, se utilizar este manejador como una referencia cuando haya que invocar las operacioues estindar del hilo reciéa creado. b) pthread_attr_t: es un atributo de creacién que se asigna con funciones es- peeificas que modifican la estructura de datos interna que almacena las caracte- risticas iniciales de creacién, entre Ins que se encuentran el tamafto de la pila pata guardar variables del hilo, con qué politica ser planificado (tiempo real, tiempo compattido), si otto bilo puede esperar sus tetminaciéa invocando pth- read. join ()o si se trata de un hilo del sistema (independiente), ver Figura 8.1. ©) void * (nombre _funcioa) (void): se ha de sustituis con el nombre de la fancién que ha de ejecutar el hilo. d) void *azgs: es un puntero al comienzo de la lista de argumentos de Ia funcién que eecotard el hilo y que puede sustituirse pot NULL si esta no pose argu- mentos. INTRODUCCION ALA PROGRAMACION CONCURRENTE 19 Entre las causas de terminacién de un hilo creado, caben ser mencionadas las si- guientes: a) Enel caso de hilos distintos del inicial, cuando la funcién designada como tercer argumento de pthread_create () acaba su ejecucién. b)_Elhilo creado invoca la funcién pthread_exit () en su cédigo; resulta finali- zada sa eecucién por otro hilo del programa que invoca la funcién pth~ read_cencel (), indicando su identificador; el mismo proceso UNIX en cuyo Ambito se cred el hilo termina con la llamada exit () « ©) Elhilo asociado a la funcién main() tetmina de ejecutarse sin que se haya llamado a la funcién pthread _exit (), que le haria terminar como un hilo més del programa. Ejemplio1.1 Como ejemplo de creacién de hilos POSIX vamos a realizar un programa que implementa un planificador de avisos, que los usuatios del sistema podrian llegar a utilizar como una agenda de funcionslidad muy basica. La interfaz de usuario del programa de este ejemplo es muy solo admite peticiones de avisos textuales. La funcionalidad del programa se resume como sigue: a) Seaceptarin continuamente, dentro de un bucle, peticiones del usuario, b) En cada una de dichas peticiones se introduce una linea completa de texto, hasta que se detecte ua erzor 0 se encuentze el fin de archivo en stain. ©) En cada linea del texto de la entrada, el primer simbolo que se puede formar es inter- pretado como el ntimero de segundos de espera hasta mostear el texto del aviso. 4d) Resto de la linea (hasta 64 caracteres) contendes el mensaje de aviso. La estructura del programa se organiza de acuerdo con varias secciones o fases; en la pri- mera de estas se realizan las siguientes declaraciones: + Declaracién de las bibliotecas a importar. + Tipo de datos global (paquete_controt) donde guardar los segundos de suspensién y el mensaje de aviso. + Recursos (archivo fp donde almacenat los avisos tealizados) Winclude #include #include typedef struct paquete_control{ int segundos; char mensaje (64); } paquete_control_ty FILE *fp; + La funcién aviso() seria el c6digo comin a todas los hilos de nuestro programa. Cada hilo que cjecute esta funcién de, forma independiente, se suspendesé durante el atimero 20 PROGRAMACION CONCURRENTE Y EN TIEMPO REAL ? de segundos especificado en su paquete de control y cuando pase de nuevo al estado activo (Salida de la suspensi6n), imprimiré la cadena con el mensaje del usuario, + Lapropia funcién avis () que ha de ejecutat cada hilo encatgado de tratar completa- mente la peticién de un aviso: void *aviso(void *arg) ( paquete_control_t “pet = (paquete_control_t *) arg? int estado; estado = pthread_detach (pthread_self()}+ if (estado ! = 0) fprintf (stderr, "hilo aviso\n"), exit(0); sleep (pcontrol->sequndos} + Eprint£ (fp, " (3) $6\n",pct->segundos, pct->mensaje) + free (pet) return Ul } La foacién anterior se encarga de convertir el argumento con que se la llama a un puntero 4 una estructuta del tipo paquete_control_t definida anteriormente. Con la llamada a la fun- eién pthzead_detach() se ocasiona que este hilo no dependa del hilo principal (es decir, el hilo de la funci6n main{) del programa). De esta forma, el hilo ocupati los recursos por separado, también puede existir por separado y ejecutarse incluso si el hilo psincipal termina de ejecutarse (siempre que el proceso UNTX que las contiene no termine). La funcién sleep i) suspende la ejecucién del hilo el mimezo de seguados (int) que s¢ le pase como parimetro. Cuando salga de Ja suspensidn, el hilo escribiri en el archivo ¢p los segundos de suspensién y el contenida del mensaje de aviso que indicé el usuario. Por iiltimo, se libera la memoria dindmica asignada a la variable pet del tipo paquete_control. Todos los hilos aviso creados en el programa comparten el mismo espacio de direcciones de memoria del proceso UNIX que les sitve de soporte de ejecucién, por lo que se crea una estructura dindmica del tipo paquete_controt_t con la llamada a la funcién malioc(), que contenga los valores del plazo de tiempo y del mensaje de aviso asociados a cada nueva peticion del usuario, Un puntero a dicha estructura ha de ser pasado como el cuarto parimetro en la mada a la funciéa pthread_create() ena funcién main(). Adems, no hay necesidad de que el hilo principal espese a que terminen todos los hilos de aviso cuya ejecucién haya lanzado el programa, poz eso se ctearon con la opcida de hilos no-reunibles 0 drtarhed. Los recursos que utilicen los hilos, al terminar su ejecucidn, seriin devueltos automiticamente al sistema cuando el programa completo termine. while (1) printf ("Pevicion de aviso> "); Af (fgets(Linea, sizeof (linea), stdin) == NULL) exit (0); if (strlen (linea) < = 1) continver pcontrol = (paquete_control_t *) malloc (sizeof (paquete_control_t))? if (pcontrol == NULL)” fprintf(stderr, "asignar memoria a pcontrol\a"), exit (0); INTRODUCCION A LA PROGRAMACION CONCURRENTE 21 if (escant (Linea, "td864[*\n)", apcontrol->segundos, pcontrol->men- e)<2) { S087 (peontrol->segundos == -1) break: felse( fprintf(stderr, "Entrada erronea\n"l; free (pcontrol) + _create(shilo, NULL, aviso, pcontrol); ig (estado ! = 0) fprint¢(stderr, "Error al crear hilo aviso\n"), exit (0)? } ig (fclose(fp)) fprintf(stderr, "Error al cerrar el fichero\n"); I hilo principal, que sirve de soporte de ejecucida al programa completo, es cl encargado de sjecutar la funcidn main (), que incluye la llamada a la funcién pthzead_create() para lanzar Ia ejecucidn de un hilo independiente, en cada iteracibn del bucle de control incondicional, hasta que el usuario envie una linea en blanco 0 indique al valor -1 en los segundos de suspensi6n, que se interpretard como una forma correcta de terminacién del programa. La linea en blanco oca- siona que todo el programa termine, utilizando pata ello la lamada a exit (0) del proceso, sin esperat la terminacién de alguin hilo de aviso atin pendiente. 1.4. Mecanismos de sincronizaci6n de bajo nivel en memoria compartida Para poder implementar mecanismos de sincronizacién en algunos lenguajes de progra- macién concurrente de alto nivel se utilizan, sin embargo, instracciones de muy bajo nivel que aprovechan la naturaleza sincrona del hardware, Dichos mecanismos consisten bisicamente en convertir a un proceso concurrente en no interrumpible utilizando para ello una instruccién de ensamblador o bien aprovechat el hecho de que el hardware de memoria solo puede servir una peticién al mismo tiempo secuencializando, de esta forma, el acceso a determinadas variables del programa, lo que podria inducir que se aparezcan condiciones de carrera entre los procesos concutrentes que, en general, no son deseables. 1.4.1. Inhibicién de las interrupciones En este caso, se utilizaré una instruccién maquina para prohibie las interrupciones del sistema'!, Nuevas interrapciones son pospuestas hasta que el proceso activo ejecute una instrucciéa que las vuelva a permitit. Si un proceso antes de ejecutar una seccién critica consigue que se prohiban las interrupciones, entonces tiene la seguridad de estar *: Obviamente, nos rferimos prineipalmente ala interupién que ocasiona la xeplanifieacién de los peocesos concu- stentes, por ejemplo, mediante ren, ya que las intemupciones hardware no pueden ser inhbidas sin que dee de fancionas el computador.

You might also like