1. Indice de pagina
  2. 1. Objetivos
  3. 2. Enunciado
  4. 2.1. Pistas
  5. 2.2. Código de inicio
  6. 2.3. Funciones necesarias
  7. 3. Solución
  8. 3.1. Código
  9. 3.2. Salida

Send & Receive

Objetivos

Enunciado

Queremos hacer un programa paralelo que encadene el envío y recepción de un mensaje, en nuestro caso el mensaje sera el rango (identificador) del proceso que envía.
Los mensajes se enviarán de forma encadenada, lo que quiere decir que el primero enviará un mensaje al segundo, el segundo recibirá uno del primero y enviará uno al tercero, y así sucesivamente para todos los procesos lanzados.
Todo proceso que reciba un mensaje debe imprimirlo de la forma "Soy el proceso X y he recibido M", siendo X el rango del proceso y M el mensaje recibido.

Imagen SendReceive Tutorial (Pulsar sobre la imagen para ver la animación)

Pistas

Recuerda inicializar y finalizar las estructuras de paralelismo aprendidas en el tutorial anterior (MPI_Init y MPI_Finalize).

Recuerda obtener el rango y el total de procesos participantes.

Ten en cuenta que el último proceso no envía ningún mensaje.

Si observas la documentación de MPI_Send y MPI_Recv se puede especificar a quien se envía o de quien se recibe un mensaje. Estas funciones reciben el mensaje siempre por referencia ( MPI_Send(&rank, .... ), MPI_Recv(&buzon, .... ) ).

Código de inicio Descarga

En este código de inicio se puede ver el funcionamiento de las funciones de envío y recepción. Lo que hace es que cada proceso se envía a sí mismo el mensaje deseado.

#include "mpi.h"
#include <iostream>
using namespace std;
 
int main(int argc, char *argv[])
{
    int rank, contador;
    MPI_Status estado;
 
    MPI_Init(&argc, &argv); // Inicializamos la comunicacion de los procesos
    MPI_Comm_rank(MPI_COMM_WORLD, &rank); // Obtenemos el valor de nuestro identificador
 
    //Envia y recibe mensajes
    MPI_Send(&rank //referencia al vector de elementos a enviar
            ,1 // tamaño del vector a enviar
            ,MPI_INT // Tipo de dato que envias
            ,rank // pid del proceso destino
            ,0 //etiqueta
            ,MPI_COMM_WORLD); //Comunicador por el que se manda
 
    MPI_Recv(&contador // Referencia al vector donde se almacenara lo recibido
            ,1 // tamaño del vector a recibir
            ,MPI_INT // Tipo de dato que recibe
            ,rank // pid del proceso origen de la que se recibe
            ,0 // etiqueta
            ,MPI_COMM_WORLD // Comunicador por el que se recibe
            ,&estado); // estructura informativa del estado
 
	cout<< "Soy el proceso "<<rank<<" y he recibido "<<contador<<endl;
 
    MPI_Finalize();
    return 0;
}

Funciones necesarias

Solución

Código Descarga

#include "mpi.h"
#include <iostream>
using namespace std;
 
int main(int argc, char *argv[])
{
    int rank, size, contador;
    MPI_Status estado;
 
    MPI_Init(&argc, &argv); // Inicializamos la comunicacion de los procesos
    MPI_Comm_size(MPI_COMM_WORLD, &size); // Obtenemos el numero total de hebras
    MPI_Comm_rank(MPI_COMM_WORLD, &rank); // Obtenemos el valor de nuestro identificador
 
    if(rank == 0){
 
        MPI_Send(&rank //referencia al vector de elementos a enviar
                ,1 // tamaño del vector a enviar
                ,MPI_INT // Tipo de dato que envias
                ,rank+1 // pid del proceso destino
                ,0 //etiqueta
                ,MPI_COMM_WORLD); //Comunicador por el que se manda
 
    }else{
 
        MPI_Recv(&contador // Referencia al vector donde se almacenara lo recibido
                ,1 // tamaño del vector a recibir
                ,MPI_INT // Tipo de dato que recibe
                ,rank-1 // pid del proceso origen de la que se recibe
                ,0 // etiqueta
                ,MPI_COMM_WORLD // Comunicador por el que se recibe
                ,&estado); // estructura informativa del estado
 
        cout<<"Soy el proceso "<<rank<<" y he recibido "<<contador<<endl;
        contador++;
        if(rank != size-1)
            MPI_Send(&contador, 1 ,MPI_INT ,rank+1 , 0 ,MPI_COMM_WORLD);
 
    }
 
    // Terminamos la ejecucion de las hebras, despues de esto solo existira
    // la hebra 0
    // ¡Ojo! Esto no significa que las demas hebras no ejecuten el resto
    // de codigo despues de "Finalize", es conveniente asegurarnos con una
    // condicion si vamos a ejecutar mas codigo (Por ejemplo, con "if(rank==0)".
    MPI_Finalize();
    return 0;
}

Obtenido el numero de procesos (size) y el rango (rank) el envio del mensaje se realiza al proceso con un rango mayor en una unidad, por tanto el proceso con ese rango debe indicar que quiere recibir un mensaje del proceso con un rango inferior en una unidad al suyo.
En nuestro programa debemos hacer una distinción ya que no todos los procesos hacen lo mismo, el primero no recibirá de nadie y el ultimo no enviara a nadie, esto se puede especificar mediante condiciones que filtren el rango del proceso.

Salida

> mpiCC 2_Send_Receive.cpp -o sendrecv
> mpirun -np 8 sendrecv

Soy el proceso 1 y he recibido 0
Soy el proceso 2 y he recibido 1
Soy el proceso 3 y he recibido 2
Soy el proceso 4 y he recibido 3
Soy el proceso 5 y he recibido 4
Soy el proceso 6 y he recibido 5
Soy el proceso 7 y he recibido 6
Creado por: Daniel Guerrero Martínez y Sergio Rodríguez Lumley 2010

Valid HTML 4.01 Transitional