27.01.2015 Views

Tema 4: SISTEMAS BASADOS EN PASO DE MENSAJES

Tema 4: SISTEMAS BASADOS EN PASO DE MENSAJES

Tema 4: SISTEMAS BASADOS EN PASO DE MENSAJES

SHOW MORE
SHOW LESS
  • No tags were found...

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

<strong>Tema</strong> 4. Sistemas basados en paso<br />

de mensajes<br />

Programación Concurrente<br />

Depto. de Lenguajes y Sistemas Informáticos<br />

Universidad de Granada


Contenidos<br />

1. Introducción<br />

2. Sentencias básicas de paso de mensajes<br />

2.1. Sentencias bloqueantes<br />

2.2. Sentencias no bloqueantes<br />

3. Espera selectiva<br />

4. La Interfaz de Paso de Mensajes (MPI)<br />

4.1. Modelo de Programación<br />

4.2. Funciones básicas<br />

4.3. Comunicación no bloqueante


1. Introducción<br />

• Multicomputador-programación distribuida / Multiprocesador progr. con<br />

memoria compartida<br />

– Extensiones de la máquina de Von-Neuman<br />

– Multiprocesador ⇒ Memoria Compartida<br />

• Más fácil programación<br />

• Mayor Coste: Acceso a Memoria Común = cuello de botella<br />

• Escalabilidad Hardware limitada<br />

– Solución: Multicomputador ⇒ Distribución de los datos/recursos<br />

• Necesidad de una notación de programación distribuida<br />

– Lenguajes tradicionales (memoria común)<br />

• Asignación: Cambio del estado interno de la máquina.<br />

• Estructuración: Secuencia, repetición, alternación, procedimientos, etc.<br />

– Extra añadido: Envío / Recepción → Afectan al entorno externo<br />

• Tan importante como la asignación<br />

• Permiten comunicar procesos que se ejecutan en paralelo<br />

– Paso de mensajes:<br />

• Abstracción: Oculta Hardware (red de interconexión).<br />

• Se puede implementar eficientemente en todas las arquitecturas.


1. Introducción<br />

Programación con paso de mensajes<br />

• Asume espacio de direcciones particionado<br />

• Vista lógica Arquitectura<br />

– P procesos, cada uno con su espacio de direcciones propio<br />

– Interacciones requieren cooperación entre 2 procesos: propietario datos<br />

debe intervenir aunque no conexión lógica con evento tratado en receptor.<br />

• Estructura de un Programa de Paso de Mensajes<br />

– Asíncrona: Todos los procesos se ejecutan asíncronamente.<br />

– Débilmente síncrona: Los procesos se sincronizan para las interacciones.<br />

Entre interacciones, trabajan asíncronamente.<br />

• Enfoque general: Ejecución programa diferente sobre cada proceso.<br />

– Difícil en la práctica.<br />

• Enfoque común: SPMD (Single Program Multiple Data)<br />

– Código que ejecutan diferentes procesos es idéntico excepto para pequeño<br />

número de procesos.


2. Sentencias básicas de<br />

paso de mensajes<br />

Send (void *sendbuf, int nelems, int dest)<br />

Receive(void *recvbuf, int nelems, int source)<br />

• Ejemplo simple: Semántica requiere que valor recibido sea 100 en lugar<br />

de 0.<br />

P0<br />

P1<br />

a=100;<br />

receive(&a,1,0);<br />

send(&a,1,1);<br />

printf("%d\n",a);<br />

a=0;<br />

– Necesario asegurar semántica, aunque existen casos en que no es deseable.<br />

• Soporte hardware para envío/recepción: muy común<br />

– DMA (Acceso Directo a Memoria): Copiar datos entre posiciones de memoria.<br />

– Interfaces de red: Transferencia de mensajes sin intervención de la CPU.<br />

– Si “send” programa hardware de comunicación y devuelve control antes de completar<br />

• P1 recibe un 0 en lugar de 100.


2.1. Sentencias Bloqueantes<br />

• Solución bloqueante: send retorna cuando se garantice semántica<br />

(seguridad).<br />

– No significa que receptor haya recibido el dato<br />

– 2 mecanismos: no buferizado /buferizado<br />

2.1.1. Send-Receive bloqueante no buferizado<br />

• Send no retorna hasta receive correspondiente encontrado en<br />

receptor<br />

• Exige cita entre emisor y receptor. No hay búfer.<br />

1. Emisor envía petición comunicación a receptor y espera confirmación.<br />

2. Receptor sólo responde a petición cuando encuentra receive.<br />

3. Tras recibir confirmación, Emisor inicia transferencia.


2.1. Sentencias Bloqueantes<br />

2.1.1. Send-Receive bloqueante no buferizado<br />

Inconvenientes:<br />

• Sobrecarga por espera ociosa:<br />

– Adecuado sólo cuando send/receive se inician aprox. mismo tiempo.<br />

Emisor<br />

Receptor<br />

Emisor<br />

Receptor<br />

Emisor<br />

Receptor<br />

send<br />

Petición<br />

receive<br />

Listo<br />

datos<br />

receive send<br />

Petición<br />

Listo receive<br />

datos<br />

send<br />

Petición<br />

Listo<br />

datos<br />

• Interbloqueos: Necesario alternar en intercambios<br />

– Código engorroso de escribir y difícil de depurar.<br />

P0<br />

send(&a,1,1);<br />

receive(&b,1,1);<br />

P1<br />

send(&a,1,0);<br />

receive(&b,1,0);


2.1. Sentencias Bloqueantes<br />

2.1.2. Send-Receive bloqueante buferizado<br />

• Emisor/Receptor tienen búfer preasignado para comunicación.<br />

– Emisor copia datos a búfer y continúa tras copia (es seguro).<br />

– Cuando receptor encuentra “receive”, comprueba si el mensaje está disponible en el búfer de<br />

recepción y copia datos en dirección destino.<br />

a) Con hardware de comunicación: Transferencia se inicia tras copia a búfer.<br />

b) Sin hardware especializado: sólo se buferiza un lado ---> menor sobrecarga<br />

• Emisor interrumpe receptor y ambos procesos intervienen en transferencia.<br />

• Receptor encuentra “receive” y mensaje es copiado al búfer de recepción.<br />

• También posible al revés (receptor interrumpe emisor).<br />

a)<br />

Emisor<br />

Receptor<br />

b)<br />

Emisor<br />

Receptor<br />

send<br />

datos<br />

receive<br />

send<br />

datos<br />

Copia en búfer<br />

de recepción<br />

receive


2.1. Sentencias Bloqueantes<br />

2.1.2. Send-Receive bloqueante buferizado<br />

• Alivia sobrecargas de espera ociosa a costa de gestión de búfer.<br />

• Sólo menos ventajosas en programas altamente síncronos o cuando la<br />

capacidad del búfer sea un asunto crítico.<br />

• Impacto de búfer finito: Escribir programas con requisitos de búfer acotados<br />

– P1 más lento que P0 ⇒ P0 podría continuar siempre que hubiese búfer.<br />

– Búfer agotado ⇒ P0 se bloquearía.<br />

P0<br />

for (i=0;i


2.2. Sentencias no bloqueantes<br />

• Protocolos bloqueantes: Garantizan semántica<br />

– sobrecarga de espera ociosa (no buferizado)<br />

– sobrecarga de gestión de búfer (buferizado)<br />

• Posibilidad: Requerir programador asegure semántica y usar<br />

operaciones send/receive con baja sobrecarga.<br />

– Las operaciones devuelven el control antes de que sea seguro modificar datos.<br />

– Responsabilidad usuario: asegurar que no se alteran los datos.<br />

– Sentencias de chequeo de estado: indican si la semántica podría violarse.<br />

• Iniciada la operación, el usuario puede realizar cualquier cómputo que no<br />

dependa de la finalización de la operación.<br />

• Cuando necesario se chequea el fin de la operación.<br />

• También existen dos posibilidades:<br />

– Buferizado<br />

– No buferizado


2.2. Sentencias no bloqueantes<br />

2.2.1. Send-Receive no bloqueante no buferizado<br />

• Proceso que desea enviar informa de un mensaje pendiente y continúa.<br />

– El programa puede hacer mientras otro trabajo.<br />

– Cuando el “receive” es confirmado, la comunicación se inicia.<br />

– Operación de chequeo indica si es seguro tocar los datos.<br />

• Mejora: Tiempo de espera ociosa se puede emplear en computación<br />

– Coste: reestructuración programa.<br />

– Con hardware especializado: sobrecarga podría ser enteramente enmascarada<br />

aunque los datos a recibir son inseguros hasta finalizar transferencia.<br />

a) Sin soporte<br />

Hardware<br />

send<br />

Emisor<br />

Petición<br />

Receptor<br />

Emisor Receptor<br />

b) Con soporte<br />

Hardware<br />

send Petición<br />

Inseguro actualizar<br />

datos a enviar<br />

Listo<br />

datos<br />

receive<br />

Inseguro actualizar<br />

datos a enviar<br />

Listo<br />

datos<br />

receive<br />

Inseguro actualizar<br />

datos a recibir


2.2. Sentencias no bloqueantes<br />

2.2.2. Send-Receive no bloqueante buferizado<br />

• Emisor inicia una operación de DMA y retorna inmediatamente.<br />

– Los datos se vuelven seguros en el momento en que DMA<br />

completado.<br />

• En el receptor, “receive” inicia la transferencia desde el búfer<br />

del emisor a la dirección destino en el receptor.<br />

• Efecto: reducir el tiempo durante el cual los datos son<br />

inseguros.<br />

• MPI implementa tanto operaciones bloqueantes como no<br />

bloqueantes.<br />

– Operaciones bloqueantes facilitan una programación más fácil y<br />

segura.<br />

– Operaciones no bloqueantes permiten optimizar el rendimiento al<br />

enmascarar sobrecargas de comunicación.


3. Espera Selectiva<br />

• Los modelos basados en paso de mensajes imponen ciertas<br />

restricciones<br />

– No basta con send y receive para modelar la semántica deseada.<br />

• Productor Consumidor con búfer de tamaño fijo<br />

– Se asumen operaciones bloqueantes sin búfer<br />

– Problema: Acoplamiento forzado entre los procesos<br />

PROC Productor<br />

{<br />

while (true){<br />

....<br />

Produce (&dato)<br />

send (&dato,1,Consumidor)<br />

....}<br />

}<br />

PROC Consumidor<br />

{<br />

while (true){<br />

....<br />

receive (&dato,1,Productor)<br />

Consume (dato)<br />

....}<br />

}


3. Espera Selectiva<br />

• Mejora: Gestión intercambio mediante proceso Buffer<br />

– Productor puede continuar después envío<br />

– Problema: El búfer sólo puede esperar mensajes de un único emisor en<br />

cada instante.<br />

• Aspecto común en aplicaciones cliente-servidor<br />

– No se conoce a priori el cliente que hace la petición en cada instante<br />

– Servidor debe estar preparado para recibir sin importar orden<br />

PROC Productor<br />

{<br />

while (true){<br />

....<br />

Produce (&dato)<br />

send (&dato,1,Buffer)<br />

....}<br />

}<br />

PROC Buffer<br />

{<br />

while (true){<br />

....<br />

receive (&dato,1,Productor)<br />

receive (&señal,1,Consumidor)<br />

send (&dato,1,Consumidor)<br />

....}<br />

}<br />

PROC Consumidor<br />

{<br />

while (true){<br />

....<br />

send (&señal,1,Buffer)<br />

receive (&dato,1,Buffer)<br />

Consume (dato)<br />

....}<br />

}


3. Espera Selectiva<br />

• Solución: Espera selectiva con varias alternativas guardadas<br />

– Se evalúan todas las guardas (condiciones)+alternativas<br />

– Elección aleatoria entre las que:<br />

• Emparejen con envío y cuyas guardas se evaluaron como ciertas<br />

– Se ejecutan las sentencias de la alternativa seleccionada<br />

– No emparejamiento ⇒ Bloqueo hasta evento<br />

– Existe select con prioridad<br />

– Evaluación guardas<br />

• Una vez al comienzo sentencia<br />

• Sólo se reevaluarán si se<br />

vuelve a ejecutar el select<br />

– Son opcionales:<br />

• la guarda y<br />

• la sentencia de recepción<br />

SELECT {<br />

condición1, receive (&mensaje1,count1, fuente1);<br />

;<br />

or<br />

condición2, receive (&mensaje2,count2, fuente2);<br />

;<br />

or<br />

…..<br />

or<br />

condiciónN, receive (&mensajeN, countN, fuenteN);<br />

;}


3. Espera Selectiva<br />

• Productor consumidor con buffer de tamaño fijo<br />

– Buffer no conoce a priori orden de peticiones (Inserción/Extracción)<br />

– Guardas controlan condiciones de sincronización (seguridad)<br />

– ¿Cuándo termina buffer<br />

• Sentencia select con temporizador (timeout).<br />

PROC Buffer<br />

const tam=10;<br />

int buf[tam], cont=0, in=0, out=0;<br />

{while (true){<br />

SELECT {<br />

PROC Productor {<br />

for(i=0;i

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!