Коммуникации точка-точка в MPI
В коммуникациях типа «точка-точка» участвуют два процесса (как частный случай процесс может посылать сообщения сам себе). Существуют различные варианты функций отправки и приема сообщений: блокирующие и не блокирующие, с буферизацией, с синхронизацией и по готовности.
Рассмотрим функции блокирующей передачи сообщений – MPI_Send и MPI_Recv:
int MPI_Send(void* buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm)
Данная функция отправляет данные, находящиеся по адресу buf в количестве count типа datatype процессу с рангом dest с тэгом сообщения tag. Посылка сообщения происходит в коммуникаторе comm. Параметр tag необходим для того, чтобы отличать сообщения от одного и того же процесса, либо сообщения от разных процессов, если принимающий процесс ожидает сообщение от любого процесса.
int MPI_Recv(void* buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Status *status) – Принимает данные и записывает их по адресу buf в количестве count типа datatype от процесса с рангом dest с тэгом сообщения tag. Прием сообщения происходит в коммуникаторе comm. По адресу status в структуру типа MPI_Status записывается информация о прошедшем приеме сообщения.
typedef struct MPI_Status {
int count; //Сколько байт получено
int cancelled; //Была ли передача прервана
int MPI_SOURCE; //От кого сообщение
int MPI_TAG; //Тэг сообщения
int MPI_ERROR; //Код ошибки
} MPI_Status;
Функции MPI_Send и MPI_Recv являются блокирующими. Возвращение из MPI_Send не происходит до тех пор, пока данные сообщения не будут скопированы во внутренний буфер MPI. MPI_Recv возвращает управление только после того, как сообщение было принято, таким образом, возможно появление взаимных блокировок процессов (deadlock) - ситуаций при который несколько процессов находятся в состоянии бесконечного ожидания ресурсов, занятых самими этими процессами. Блокировка может произойти в случае, когда два процесса попытаются обменяться сообщениями при помощи одинаковой последовательности вызовов (на примере процессов с рангами 0 и 1):
MPI_Send(buffer, 100, MPI_CHAR, !rank, 1, MPI_COMM_WORLD);
MPI_Recv(buffer, 100, MPI_CHAR, !rank, 1, MPI_COMM_WORLD,&st);
Блокировка здесь произойдет сразу во время вызова MPI_Send, так как оба процесса пытаются отправить данные, но ни один еще не начал их принимать. Для избежания таких ситуаций могут использоваться функции совмещенного приема и передачи данных MPI_Sendrecv и
MPI_Sendrecv_replace:
int MPI_Sendrecv(void *sendbuf, int sendcount, MPI_Datatype sendtype,
int dest, int sendtag,
void *recvbuf, int recvcount, MPI_Datatype recvtype,
int source, int recvtag,
MPI_Comm comm, MPI_Status *status)
Буфера sendbuf и recvbuf не должны пересекаться. Если необходимо обменяться данными, то следует использовать функцию MPI_Sendrecv_replace.
int MPI_Sendrecv_replace(void *buf, int count, MPI_Datatype datatype,
int dest, int sendtag, int source, int recvtag,
MPI_Comm comm, MPI_Status *status)
Ниже приведен пример обмена данными двух процессов с рангами 0 и 1 при помощи вызова MPI_Sendrecv_replace:
#include <mpi.h>
#include <stdio.h>
static char data[100];
int main(int argc, char** argv)
{
int rank,size;
MPI_Status st;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD,&rank);
if (size!=2)
{
printf("This example should be run on 2 processors \n");
MPI_Finalize();
return 0;
}
if(rank==0) {
sprintf(data, “message from process 0 ”);
} else {
sprintf(data, “message from process 1 ”);
} MPI_Sendrecv_replace(&data,100, MPI_INT, !rank, 0,!rank,0,MPI_COMM_WORLD,&st);
printf("Process %d got %s. \n", rank, data);
MPI_Finalize();
return 0;
}
Результат работы:
Process 0 got message from process 1.
Process 1 got message from process 0.
Дата добавления: 2016-05-31; просмотров: 2225;