Tema 4: SISTEMAS BASADOS EN PASO DE MENSAJES
Tema 4: SISTEMAS BASADOS EN PASO DE MENSAJES
Tema 4: SISTEMAS BASADOS EN PASO DE MENSAJES
- 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