Общие сведения о функциях передачи сообщений
Практически все программы, написанные с использованием коммуникационной технологии MPI, должны содержать средства не только для порождения и завершения параллельных процессов, но и для взаимодействия запущенных процессов между собой. Такое взаимодействие осуществляется в MPI посредством явной посылки сообщений.
Все процедуры передачи сообщений в MPI делятся на две группы. В одну группу входят процедуры, которые предназначены для взаимодействия только двух процессов программы. Такие операции называются индивидуальными или операциями типа точка-точка. Процедуры другой группы предполагают, что в операцию должны быть вовлечены все процессы некоторого коммуникатора. Такие операции называются коллективными.
Рассмотрим процедуры обмена сообщениями с использованием операций типа точка-точка. В таких взаимодействиях участвуют два процесса, причем один процесс является отправителем сообщения, а другой – получателем. Процесс-отправитель должен вызвать одну из процедур передачи данных и явно указать номер в некотором коммуникаторе процесса-получателя, а процесс-получатель должен вызвать одну из процедур приема с указанием того же коммуникатора, причем в некоторых случаях он может не знать точный номер процесса-отправителя в данном коммуникаторе.
Все процедуры данной группы, в свою очередь, так же делятся на два класса: процедуры с блокировкой (с синхронизацией) и процедуры без блокировки (асинхронные). Процедуры обмена с блокировкой приостанавливают работу процесса до выполнения некоторого условия, а возврат из асинхронных процедур происходит немедленно после инициализации соответствующей коммуникационной операции. Неаккуратное использование процедур с блокировкой может привести к возникновению тупиковой ситуации, поэтому при этом требуется дополнительная осторожность. Использование асинхронных операций к тупиковым ситуациям не приводит, однако требует более аккуратного использования массивов данных.
Передача сообщения «точка-точка»
Для передачи сообщения процесс-отправитель должен выполнить функцию:
int MPI_Send(void *buf, int count, MPI_Datatype type, int dest, int tag, MPI_Comm comm)
Функция использует следующие параметры:
buf – адрес буфера памяти, в котором располагаются данные отправляемого сообщения;
count – количество элементов данных в сообщении;
type – тип элементов данных пересылаемого сообщения;
dest – ранг процесса, которому отправляется сообщение;
tag – значение-тег, используемое для идентификации сообщений;
comm – коммуникатор, в рамках которого выполняется передача данных.
Для указания типа пересылаемых данных в MPI имеется ряд базовых типов, список которых приведен в табл. 1.
Таблица 1. Соответствие типов в MPI и языке Cи
Тип MPI | Тип Cи |
MPI_CHAR | char |
MPI_BYTE | unsigned char |
MPI_SHORT | short |
MPI_INT | int |
MPI_LONG | long |
MPI_FLOAT | float |
MPI_DOUBLE | double |
MPI_UNSIGNED_CHAR | unsigned char |
MPI_UNSIGNED_SHORT | unsigned short |
MPI_UNSIGNED | unsigned int |
MPI_UNSIGNED_LONG | unsigned long |
MPI_LONG_DOUBLE | long double |
Также в MPI имеются типы MPI_BYTE и MPI_PACKED, которые не имеют соответствия в языке Си. Значением типаMPI_BYTE является байт. Байт не интерпретируется и отличен от символа. Различные машины могут иметь различное представление для символов или могут использовать для представления символов более одного байта. При этом байт имеет то же самое двоичное значение на всех машинах.
Необходимо отметить следующее:
1. Отправляемое сообщение определяется через указание блока памяти (буфера), в котором это сообщение располагается. Используемые для указания буфера три параметра (buf, count, type) входят в состав параметров практически всех функций передачи данных.
2. Процессы, между которыми выполняется передача данных, в обязательном порядке должны принадлежать коммуникатору, указываемому в функции MPI_Send.
3. Параметр tag используется только при необходимости различения передаваемых сообщений, в противном случае в качестве значения параметра может быть использовано произвольное целое число (см. также описание функции MPI_Recv).
Сразу же после завершения функции MPI_Send процесс-отправитель может начать повторно использовать буфер памяти, в котором располагалось отправляемое сообщение. Вместе с этим, следует понимать, что в момент завершения функции MPI_Send состояние самого пересылаемого сообщения может быть совершенно различным – сообщение может располагаться в процессе-отправителе, может находиться в процессе передачи, может храниться в процессе-получателе или же может быть принято процессом-получателем при помощи функции MPI_Recv. Тем самым, завершение функции MPI_Send означает лишь, что операция передачи начала выполняться и пересылка сообщения будет рано или поздно будет выполнена.
Прием сообщений «точка-точка» с блокировкой
Для приема сообщения процесс-получатель должен выполнить функцию
int MPI_Recv(void *buf, int count, MPI_Datatype type, int source, int tag, MPI_Comm comm, MPI_Status *status)
Функция использует следующие параметры:
buf, count, type – буфер памяти для приема сообщения, назначение каждого отдельного параметра соответствует описанию в MPI_Send;
source – ранг процесса, от которого должен быть выполнен прием сообщения;
tag – тег сообщения, которое должно быть принято для процесса;
comm – коммуникатор, в рамках которого выполняется передача данных;
status – указатель на структуру данных с информацией о результате выполнения операции приема данных.
Отметим следующее:
1. Буфер памяти должен быть достаточным для приема сообщения, а тип элементов передаваемого и принимаемого сообщения должны совпадать; при нехватке памяти часть сообщения будет потеряна и в коде завершения функции будет зафиксирована ошибка переполнения.
2. При необходимости приема сообщения от любого процесса-отправителя для параметра source может быть указано значение MPI_ANY_SOURCE.
3. При необходимости приема сообщения с любым тегом для параметра tag может быть указано значение MPI_ANY_TAG.
4. Параметр status позволяет определить ряд характеристик принятого сообщения:
status.MPI_SOURCE – ранг процесса-отправителя принятого сообщения;
status.MPI_TAG – тег принятого сообщения.
При необходимости можно пользоваться функцией
MPI_Get_count(MPI_Status *status, MPI_Datatype type, int *count)
которая возвращает в переменной count количество элементов типа type в принятом сообщении.
Вызов функции MPI_Recv не должен согласовываться со временем вызова соответствующей функции передачи сообщения MPI_Send – прием сообщения может быть инициирован до момента, в момент или после момента начала отправки сообщения.
По завершении функции MPI_Recv в заданном буфере памяти будет располагаться принятое сообщение. Принципиальный момент здесь состоит в том, что функция MPI_Recv является блокирующей для процесса-получателя, т.е. его выполнение приостанавливается до завершения работы функции. Таким образом, если по каким-то причинам ожидаемое для приема сообщение будет отсутствовать, выполнение параллельной программы будет блокировано.
Рассмотрим пример программы с использованием функций передачи сообщений.
#include <stdio.h>
#include "mpi.h"
int main(int argc, char* argv[])
{
Дата добавления: 2016-02-02; просмотров: 1072;