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.
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, .... ) ).
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; }
#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.