Двухточечные обмены
Двухточечный обмен с буферизацией
Передача сообщения в буферизованном режиме может быть начата независимо от того, зарегистрирован ли соответствующий прием. Источник копирует сообщение в буфер, а затем передает его в неблокирующем режиме.
Размер буфера должен превосходить размер сообщения на величину 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)