- •Реферат
- •1. Mpi_Init, mpi_Finalize, “Hello, World” с анализом результата mpi_Init
- •---------------------------------------------------------------------------
- •2. Mpi_Send, mpi_Recv, анализ структуры mpi_Status
- •-----------------------------------------------------------------------------------------------------------------
- •3. Разрешение взаимной блокировки Send/Recv с помощью функции mpi_Sendrecv
- •------------------------------------------------------------------------
- •4. Пример использования mpi_Waitall, mpi_Waitany
- •--------------------------------------------------
- •5. Пример использования mpi_Bcast
- •--------------------------------------------------------------------------
- •6. Пример использования mpi_Gatherv и mpi_Scatterv
-----------------------------------------------------------------------------------------------------------------
3. Разрешение взаимной блокировки Send/Recv с помощью функции mpi_Sendrecv
Пример взаимной блокировки этих двух функций:
Допустим, у нас есть несколько процессов, которые взаимодействуют следующим образом:

Каждый процесс содержит следующий код:
for(i=0; i<n; i++)
{
MPI_Send(…);
}
for(i=0; i<n; i++)
{
MPI_Recv(…);
}
Если запустить эти процессы, мы получим тупик, так как процессы зайдут в функцию MPI_Send() и будут ждать ее завершения. А для ее завершения необходимо выполнение функции MPI_Recv, которая никогда не выполнится.
Чтобы избежать взаимной блокировки можно выполнить взаимный обмен данными между процессами, используя совмещенную операцию MPI_Sendrecv.
int MPI_Sendrecv(void *sbuf, int scount, MPI_Datatype stype, int dest, int stag, void *rbuf, int count, MPI_Datatype rtype, int source, int rtag, MPI_Comm comm, MPI_Status *status), где
sbuf, scount, stype, dest, stag — параметры передаваемого сообщения;
rbuf, rcount, rtype, source, rtag — параметры принимаемого сообщения;
comm — коммуникатор, в рамках которого выполняется передача данных;
status — структура данных с информацией о результате выполнения операции.
Тогда каждый процесс будет содержать следующий код:
for(i=0; i<n; i++)
{
MPI_Sendrecv(…);
}
------------------------------------------------------------------------
4. Пример использования mpi_Waitall, mpi_Waitany
Процедура MPI_Waitall:
int MPI_Waitall(int count, MPI_Request *requests, MPI_Status *statuses), где
– count - число идентификаторов;
– requests - массив идентификаторов асинхронного приема или передачи;
– OUT statuses - параметры сообщений.
Выполнение процесса блокируется до тех пор, пока все операции обмена, ассоциированные с указанными идентификаторами, не будут завершены. Если во время одной или нескольких операций обмена возникли ошибки, то поле ошибки в элементах массива statuses будет установлено в соответствующее значение.
Пример. Сеть из 4 узлов с круговой топологией. Каждый узел посылает двум соседям сообщения и ждет ответа от них. Работа каждого узла не завершится до тех пор, пока все 4 операции не будут выполнены.
# include <mpi.h>
# include <stdio.h>
int main(int argc, char** argv)
{
int numtasks, rank, next, prev, buf[2], tag1 = 1, tag2 = 2;
MPI_Request reqs[4];
MPI_Status stats[4];
MPI_Init(&argc,&argv);
MPI_Comm_size(MPI_COMM_WORLD, &numtasks);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
prev = rank - 1;
next = rank + 1;
if (rank == 0) prev = numtasks - 1;
if (rank == (numtasks - 1)) next = 0;
MPI_Irecv(&buf[0], 1, MPI_INT, prev, tag1, MPI_COMM_WORLD, &reqs[0]);
MPI_Irecv(&buf[1], 1, MPI_INT, next, tag2, MPI_COMM_WORLD, &reqs[1]);
MPI_Isend(&rank, 1, MPI_INT, prev, tag2, MPI_COMM_WORLD, &reqs[2]);
MPI_Isend(&rank, 1, MPI_INT, next, tag1, MPI_COMM_WORLD, &reqs[3]);
MPI_Waitall(4, reqs, stats);
printf("Node %d: all ok!\n", rank);
MPI_Finalize();
}
Результат выполнения программы на 4 процессах:
Node 1: all ok!
Node 3: all ok!
Node 2: all ok!
Node 0: all ok!
Процедура MPI_Waitany:
int MPI_Waitany(int count, MPI_Request *requests, int *index, MPI_Status *status), где
– count - число идентификаторов;
– requests - массив идентификаторов асинхронного приема или передачи;
– OUT index - номер завершенной операции обмена;
– OUT status - параметры сообщений.
Выполнение процесса блокируется до тех пор, пока какая-либо операция обмена, ассоциированная с указанными идентификаторами, не будет завершена. Если несколько операций могут быть завершены, то случайным образом выбирается одна из них. Параметр index содержит номер элемента в массиве requests, содержащего идентификатор завершенной операции.
Пример. Изменим предыдущий пример используя функциюMPI_WaitanyвместоMPI_Waitall.
# include <mpi.h>
# include <stdio.h>
int main(int argc, char** argv)
{
int numtasks, rank, next, prev, buf[2], tag1 = 1, tag2 = 2;
int *i;
MPI_Request reqs[4];
MPI_Status stats[4];
MPI_Init(&argc,&argv);
MPI_Comm_size(MPI_COMM_WORLD, &numtasks);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
prev = rank - 1;
next = rank + 1;
if (rank == 0) prev = numtasks - 1;
if (rank == (numtasks - 1)) next = 0;
MPI_Irecv(&buf[0], 1, MPI_INT, prev, tag1, MPI_COMM_WORLD, &reqs[0]);
MPI_Irecv(&buf[1], 1, MPI_INT, next, tag2, MPI_COMM_WORLD, &reqs[1]);
MPI_Isend(&rank, 1, MPI_INT, prev, tag2, MPI_COMM_WORLD, &reqs[2]);
MPI_Isend(&rank, 1, MPI_INT, next, tag1, MPI_COMM_WORLD, &reqs[3]);
MPI_Waitany(4, reqs, &i, stats);
printf("Node %d: all ok!\n", rank);
MPI_Finalize();
}
Результат выполнения программы на 4 процессах:
Node 1: all ok!
Node 3: all ok!
Node 2: all ok!
Node 0: all ok!
