| Украина, г. Киев |
Двухточечные обмены
Двухточечный обмен с буферизацией
Передача сообщения в буферизованном режиме может быть начата независимо от того, зарегистрирован ли соответствующий прием. Источник копирует сообщение в буфер, а затем передает его в неблокирующем режиме.
Размер буфера должен превосходить размер сообщения на величину MPI_BSEND_OVERHEAD. Это дополнительное пространство используется подпрограммой буферизованной передачи для своих целей.
Если перед выполнением операции буферизованного обмена не выделен буфер, MPI ведет себя так, как если бы с процессом был связан буфер нулевого размера. Работа с таким буфером обычно завершается сбоем программы.
Буферизованный обмен рекомендуется использовать в тех ситуациях, когда программисту требуется больший контроль над распределением памяти. Этот режим удобен и для отладки, поскольку причину переполнения буфера определить легче, чем причину тупика.
При выполнении буферизованного обмена программист должен заранее создать буфер достаточного размера:
int MPI_Buffer_attach(void *buf, size)
MPI_Buffer_attach(buf, size, ierr)
В результате вызова создается буфер buf размером size байтов. В программах на языке Fortran роль буфера может играть массив. За один раз к процессу может быть подключен только один буфер.
Буферизованная передача завершается сразу, поскольку сообщение немедленно копируется в буфер для последующей передачи. В отличие от стандартного обмена, в этом случае работа источника и адресата не синхронизована:
int MPI_Bsend(void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm)
MPI_Bsend(buf, count, datatype, dest, tag, comm, ierr)
После завершения работы с буфером его необходимо отключить:
int MPI_Buffer_detach(void *buf, int *size)
MPI_Buffer_detach(buf, size, ierr)
Возвращается адрес (buf) и размер отключаемого буфера (size). Эта операция блокирует работу процесса до тех пор, пока все сообщения, находящиеся в буфере, не будут обработаны. Вызов данной подпрограммы можно использовать для форсированной передачи сообщений. После завершения вызова можно вновь использовать память, которую занимал буфер. В языке C данный вызов не освобождает автоматически память, отведенную для буфера.
Пример программы, использующей обмен с буферизацией
#include "mpi.h"
#include <stdio.h>
int main(int argc,char *argv[])
{
int *buffer;
int myrank;
MPI_Status status;
int buffsize = 1;
int TAG = 0;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
if (myrank == 0)
{
buffer = (int *) malloc(buffsize + MPI_BSEND_OVERHEAD);
MPI_Buffer_attach(buffer, buffsize + MPI_BSEND_OVERHEAD);
buffer = (int *) 10;
MPI_Bsend(&buffer, buffsize, MPI_INT, 1, TAG, MPI_COMM_WORLD);
MPI_Buffer_detach(&buffer, &buffsize);
}
else
{
MPI_Recv(&buffer, buffsize, MPI_INT, 0, TAG, MPI_COMM_WORLD, &status);
printf("received: %i\n", buffer);
}
MPI_Finalize();
return 0;}
Другие разновидности двухточечного обмена
Cинхронный обмен
Завершение передачи происходит только после того, как прием сообщения инициализирован другим процессом. Адресат посылает источнику "квитанцию" - уведомление о завершении приема. После получения этого уведомления обмен считается завершенным и источник "знает", что его сообщение получено:
int MPI_Ssend(void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm)
MPI_SSEND(BUF, COUNT, DATATYPE, DEST, TAG, COMM, IERR)
Обмен "по готовности"
Передача "по готовности" выполняется с помощью подпрограммы MPI_Rsend:
int MPI_Rsend(void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm) MPI_Rsend(buf, count, datatype, dest, tag, comm, ierr)
Передача "по готовности" должна начинаться, если уже зарегистрирован соответствующий прием. При несоблюдении этого условия результат выполнения операции не определен.
Совместные прием и передача
Операции приемопередачи объединяют в едином вызове передачу сообщения одному процессу и прием сообщения от другого процесса. Данный вид обменов может оказаться полезным при выполнении сложных схем обмена сообщениями, например, по цепи процессов.
Подпрограммы приемопередачи могут взаимодействовать с обычными подпрограммами обмена и подпрограммами зондирования.
Подпрограмма MPI_Sendrecv выполняет прием и передачу данных с блокировкой:
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)
MPI_Sendrecv(sendbuf, sendcount, sendtype, dest, sendtag, recvbuf, recvcount, recvtype, source, recvtag, comm, status, ierr)
Имеются разновидности операции приемопередачи.
Подпрограмма 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)
MPI_Sendrecv_replace(BUF, COUNT, DATATYPE, DEST, SENDTAG, SOURCE, RECVTAG, COMM, STATUS, IERR)