Параллельное программирование: Учебное пособие, страница 91

#include <stdio.h>

int main(int argc, char *argv[])

{

int myrank, size, message;

int TAG = 0;

MPI_Status status;

MPI_Init(&argc, &argv);

MPI_Comm_rank(MPI_COMM_WORLD, &myrank);

MPI_Comm_size(MPI_COMM_WORLD, &size);

message = myrank;

if((myrank % 2) == 0)   /* Результат деления на 2 равен 0? */

{        /* Отсылка сообщения от процесса четного ранга к нечетному */

if((myrank + 1) != size) /* Ранг процесса нечетный? */

MPI_Send(&message, 1, MPI_INT, myrank + 1, TAG,

MPI_COMM_WORLD);

}

else/* Прием сообщения процессом нечетного ранга */

   {if(myrank != 0)       /* от передавшего процесса четного ранга */

MPI_Recv(&message, 1, MPI_INT, myrank - 1, TAG,

MPI_COMM_WORLD, &status);

printf("received : %i\n", message);

}

MPI_Finalize();

return 0;

}

Результат выполнения этой программы в случае запуска 10 процессов на 10 процессорах, имена которых перечислены в файле  machines.txt, выглядит так:

mpiexec –host -machinefile -n 10 -- myprogr

received : 0

received : 6

received : 2

received : 4

received : 8

Порядок вывода сообщений может оказаться и другим, так как при параллельном выполнении этих 10 процессов скорости выполнения у каждого процесса различны и не предсказуемы.

Если стандартная передача не может быть выполнена из-за недостаточного объема приемного буфера, осуществление процесса блокируется до тех пор, пока не будет доступен буфер достаточного размера. Иногда это может оказаться удобным. Например, когда источник циклически посылает новые значения адресату и они вырабатываются быстрее, чем потребитель может их принять, то через некоторое может произойти переполнение буфера приема. Чтобы этого не допустить, в программу необходимо включить дополнительную синхронизацию. В стандартной передаче такая синхронизация выполняется автоматически.

Недостаточный размер буфера может привести и к тупиковой ситуации. Это иллюстрируется примерами текстов 5.3 и 5.4.

Текст 5.3. Пример устойчиво работающей программы

#include "mpi.h"

#include <stdio.h>

int main(int argc, char *argv[])

{

int rank, tag, cnt, status(MPI_STATUS_SIZE);

float sndbuf1, sndbuf2, rcvbuf;

int cnt = 1;

int tag = 0;

MPI_Init(&argc, &argv);

MPI_Comm_rank(MPI_COMM_WORLD, &myrank);

if (rank == 0)

{

sndbuf1 = 3.14159;

MPI_Send(&sndbuf1, cnt, MPI_FLOAT, 1, tag,

MPI_COMM_WORLD);

printf("Process %i",rank, " send %f\n", sndbuf1);

MPI_Recv(&rcvbuf, cnt, MPI_FLOAT, 1, tag,

MPI_COMM_WORLD, status)

printf("Process %i",rank,"received %f\n",rcvbuf);

}

else

{

MPI_Recv(&rcvbuf, cnt, MPI_FLOAT, 0, tag,

MPI_COMM_WORLD, status);

printf("Process %i",rank,"received %f\n",rcvbuf);

sndbuf2 = 2.71828;

MPI_Send(&sndbuf2, cnt, MPI_FLOAT, 0, tag,

MPI_COMM_WORLD);

Printf("Process %i",rank," send %f\n", sndbuf2)

};

MPI_Finalize(); return 0;

}

Вывод этой программы будет выглядеть так:

mpiexec –host HM1, HM2 -n 2 -- myprogr

Process 1 received 3.14159012

Process 1 send 2.71828008

Process 0 send 3.14159012

Process 0 received 2.71828008

Текст 5.4. Пример программы, попадающей в «тупик»

#include "mpi.h"

#include <stdio.h>

int main(int argc, char *argv[])

{

int rank, tag, cnt, status(MPI_STATUS_SIZE);

float sndbuf, rcvbuf;

int tag = 0;

sndbuf = 3.14159;

int cnt = 1;

MPI_Init(&argc, &argv);

MPI_Comm_rank(MPI_COMM_WORLD, &myrank);

if (rank == 0)

then

{

MPI_Recv(&rcvbuf, cnt, MPI_FLOAT, 1, tag,

MPI_COMM_WORLD, status)

MPI_Send(&sndbuf, cnt, MPI_FLOAT, 1, tag,

MPI_COMM_WORLD);

}

else

{

MPI_Recv(&rcvbuf, cnt, MPI_FLOAT, 0, tag,

MPI_COMM_WORLD, status);

MPI_Send(sndbuf2, cnt, MPI_FLOAT, 0, tag,

MPI_COMM_WORLD);

};

MPI_Finalize();

return 0;

}

Первая из этих программ работает нормально, а вторая попадет в "тупик", так как в ней прием сообщения процессом с рангом 0 должен завершиться до передачи им своего сообщения. Этот прием может быть осуществлен, только если процессом с рангом 1 выполнена соответствующая передача, а она, в свою очередь, может начаться только после завершения процессом 1 приема сообщения от процесса 0.