Sari la conținutul principal

Receive

MPI_Recv

MPI_Recv reprezintă funcția prin care un proces primește date de la un alt proces. Semnătura funcției este următoarea:

int MPI_Recv(void* data, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm communicator, MPI_Status* status)

Unde:

  • data (↑) - reprezintă datele primite de la procesul sursă de către procesul destinație
  • count (↓) - dimensiunea datelor primite
  • datatype (↓) - tipul datelor primite
  • source (↓) - rangul / identificatorului procesului sursă, care trimite datele
  • tag (↓) - identificator al mesajului
  • communicator (↓) - comunicatorul în cadrul căruia se face trimiterea datelor între cele două procese
  • status - conține date despre mesajul primit, MPI_Status fiind o structură ce conține informații despre mesajul primit (sursa, tag-ul mesajului, dimensiunea mesajului). Dacă nu dorim să ne folosim de datele despre mesajul primit, punem MPI_STATUS_IGNORE, prin care se ignoră status-ul mesajului.

În situația în care procesul P apelează funcția de MPI_Recv(), el se va bloca până va primi toate datele asteptate, astfel că dacă nu va primi nimic sau ceea ce primește este insuficient, P va rămâne blocat. Adică MPI_Recv() se termină doar în momentul în care buffer-ul a fost umplut cu datele așteptate.

Structura MPI_Status include următoarele câmpuri:

  • int count - dimensiunea datelor primite
  • int MPI_SOURCE - identificatorul procesului sursă, care a trimis datele
  • int MPI_TAG - tag-ul mesajului primit

MPI_Recv este o funcție blocantă, mai precis programul se poate bloca până când se execută acțiunea de trimitere a mesajului către procesul sursă.

Un exemplu de program în care un proces trimite un mesaj către un alt proces:

#include "mpi.h"
#include <stdio.h>
#include <stdlib.h>

int main (int argc, char *argv[])
{
int numtasks, rank, len;
char hostname[MPI_MAX_PROCESSOR_NAME];

MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &numtasks); // Total number of processes.
MPI_Comm_rank(MPI_COMM_WORLD,&rank); // The current process ID / Rank.
MPI_Get_processor_name(hostname, &len);

srand(42);
int random_num = rand();
printf("Before send: process with rank %d has the number %d.\n", rank,
random_num);

if (rank == 0) {
MPI_Send(&random_num, 1, MPI_INT, 1, 0, MPI_COMM_WORLD);
} else {
MPI_Status status;
MPI_Recv(&random_num, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, &status);
printf("Process with rank %d, received %d with tag %d.\n",
rank, random_num, status.MPI_TAG);
}

printf("After send: process with rank %d has the number %d.\n", rank,
random_num);

MPI_Finalize();

}
atenție

Când un proces X trimite un mesaj către un proces Y, tag-ul T al mesajului din MPI_Send, executat de procesul X, trebuie să fie același cu tag-ul mesajului din MPI_Recv, executat de procesul Y, deoarece procesul Y așteaptă un mesaj care are tag-ul T, altfel, dacă sunt tag-uri diferite, programul se va bloca.

O ilustrație a modului cum funcționează împreună funcțiile MPI_Send și MPI_Recv:

img

Mai jos aveți un exemplu în care un proces trimite un întreg array de 100 de elemente către un alt proces:

Exemplu
#include "mpi.h"
#include <stdio.h>
#include <stdlib.h>

int main (int argc, char *argv[])
{
int numtasks, rank, len;
int size = 100;
char hostname[MPI_MAX_PROCESSOR_NAME];
int arr[size];

MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &numtasks);
MPI_Comm_rank(MPI_COMM_WORLD,&rank);
MPI_Get_processor_name(hostname, &len);

srand(42);
if (rank == 0) {
for (int i = 0; i < size; i++) {
arr[i] = i;
}

printf("Process with rank [%d] has the following array:\n", rank);
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");

MPI_Send(arr, size, MPI_INT, 1, 1, MPI_COMM_WORLD);
printf("Process with rank [%d] sent the array.\n", rank);
} else {
MPI_Status status;
MPI_Recv(arr, size, MPI_INT, 0, 1, MPI_COMM_WORLD, &status);
printf("Process with rank [%d], received array with tag %d.\n",
rank, status.MPI_TAG);

printf("Process with rank [%d] has the following array:\n", rank);
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}

MPI_Finalize();
}