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

then

{

i = 2004;

MPI_Send(i, 1, MPI_INTEGER, dest, tag,

MPI_COMM_WORLD);

}

else

{

if(rank == 1)

{

x = 3.14159;

MPI_Send(x, 1, MPI_FLOAT, dest, tag,

MPI_COMM_WORLD);

}

else

{

for(k = 1, 2;;)

{

MPI_Probe(MPI_Any_source, tag,

MPI_COMM_WORLD, status);

if (status(MPI_Source) == 0)

{

MPI_Recv(i, 1, MPI_INT, 0, tag,

MPI_COMM_WORLD, status);

Printf("received ", i, " from 0");

}

else

{

MPI_Recv(x, 1, MPI_FLOAT, 1, tag,

MPI_COMM_WORLD, status);

Printf("received ", x, " from 1");

}

}

}

MPI_Finalize();

return 0;

}

В этом примере проблема заключается в том, что процессы с рангами 0 и 1 передают процессу dest=2 сообщения, содержащие данные разных типов. Порядок приема этих сообщений не определен, поэтому заранее неизвестно, данные какого типа должны быть приняты при первом вызове подпрограммы MPI_Recv, а какие — при втором. Благодаря вызову подпрограммы MPI_Probe, каждое сообщение принимается с использованием правильного типа данных.

В тексте 5.7 подпрограммы-пробники принимают сообщения от неизвестного источника, количество элементов целого типа в котором тоже неизвестно. В этом случае вместо ранга источника и тега сообщения используются джокеры. Сначала с помощью вызова подпрограммы MPI_Probe фиксируется факт наличия еще не принятого сообщения. Затем определяется источник сообщения, с помощью вызова MPI_Get_count определяется его длина, выделяется буфер подходящего размера и лишь потом выполняется прием сообщения.

Текст 5.7. Использование зондирующих подпрограмм

#include "mpi.h"

#include <stdio.h>

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

{

int myid, numprocs, **buf, source, i;

int message[3] = {0, 1, 2};

int myrank, data = 2004, count, TAG = 0;

MPI_Status status;

MPI_Init(&argc, &argv);

MPI_Comm_rank(MPI_COMM_WORLD, &myrank);

if (myrank == 0)

{

MPI_Send(&data, 1, MPI_INT, 2, TAG,

MPI_COMM_WORLD);

}

else

if (myrank ==1)

{

MPI_Send(&message, 3, MPI_INT, 2, TAG,

MPI_COMM_WORLD);

}

else

{

MPI_Probe(MPI_ANY_SOURCE, 0, MPI_COMM_WORLD,

&status);

source = status.MPI_SOURCE;

MPI_Get_count(&status, MPI_INT, &count);

for (i = 0; i < count; i++)

{

buf[i] = (int *)malloc(count *sizeof(int));

}

MPI_Recv(&buf[0], count, MPI_INT, source, TAG,

MPI_COMM_WORLD, &status);

for (i = 0; i < count; i++)

{

printf ("received: %d\n", buf[i]);

}

}

MPI_Finalize();

return 0;

}

При запуске этой программы должны создаваться три процесса:

mpiexechost-machinefile -n 3 -- myprogr

Процесс с рангом 0 передает процессу 2 сообщение, содержащее одно значение (переменная data), а процесс с рангом 1 передает тому же процессу три элемента данных в массиве message. Порядок поступления этих сообщений не определен и первым может прийти как сообщение от процесса 0, так и сообщение от процесса 1. Для того чтобы правильно организовать прием сообщения, необходимо заранее узнать его длину и, возможно, источник. Это и делают подпрограммы MPI_Probe и MPI_Get_count. В этой программе будет принято лишь одно сообщение, а второе останется в коммуникационной среде. В нормальных программах таких ситуаций не должно быть.

5.2.6  Совместные прием и передача


Выполнить в едином вызове операцию приема и передачи можно с помощью подпрограммы MPI_Sendrecv. Эта подпрограмма осуществляет передачу сообщения одному процессу, а принимает сообщение от другого процесса. Такой обмен может оказаться полезным, например, в кольцевой цепи из нескольких процессов (рис. 5.5).

Рисунок 5.5.Обмен сообщениями по кольцу из процессов.

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