Коллективные взаимодействия процессов
В операциях коллективного взаимодействия процессов участвуют все процессы коммуникатора. Соответствующая процедура должна быть вызвана каждым процессом, быть может, со своим набором параметров. Возврат из процедуры коллективного взаимодействия может произойти в тот момент, когда участие процесса в данной операции уже закончено. Как и для блокирующих процедур, возврат означает то, что разрешен свободный доступ к буферу приема или посылки. Асинхронных коллективных операций в MPI нет.
В коллективных операциях можно использовать те же коммуникаторы, что и были использованы для операций типа точка-точка. MPI гарантирует, что сообщения, вызванные коллективными операциями, никак не повлияют на выполнение других операций и не пересекутся с сообщениями, появившимися в результате индивидуального взаимодействия процессов.
Вообще говоря, нельзя рассчитывать на синхронизацию процессов с помощью коллективных операций. Если какой-то процесс уже завершил свое участие в коллективной операции, то это не означает ни того, что данная операция завершена другими процессами коммуникатора, ни даже того, что она ими начата (конечно же, если это возможно по смыслу операции).
В коллективных операциях не используются идентификаторы сообщений.
int MPI_Bcast(void *buf, int count, MPI_Datatype datatype, int source, MPI_Comm comm)
• outbuf— адрес начала буфера посылки сообщения;
• count— число передаваемых элементов в сообщении;
• datatype — тип передаваемых элементов;
• source — номер рассылающего процесса;
• comm — идентификатор коммуникатора.
Рассылка сообщения от процесса source всем процессам данного коммуникатора, включая рассылающий процесс. При возврате из процедуры содержимое буфера buf процесса source будет скопировано в локальный буфер каждого процесса коммуникатора comm. Значения параметров count, datatype, source и comm должны быть одинаковыми у всех процессов. В результате выполнения следующего оператора всеми процессами коммуникатора comm: MPI_Bcast(array, 100, MPIINT, 0, comm);
первые сто целых чисел из массива array нулевого процесса будут скопированы в локальные буфера array каждого процесса коммуникатора comm.
int MPI_Gather( void *sbuf, int scount, MPI_Datatype stype, void *rbuf, int rcount, MPI_Datatype rtype, int dest, MPI_Comm comm)
• sbuf — адрес начала буфера посылки;
• scount — число элементов в посылаемом сообщении;
• stype — тип элементов отсылаемого сообщения;
• out rbuf — адрес начала буфера сборки данных;
• rcount — число элементов в принимаемом сообщении;
• rtype — тип элементов принимаемого сообщения;
• dest — номер процесса, на котором происходит сборка данных;
• comm — идентификатор коммуникатора.
Сборка данных со всех процессов в буфере rbuf процесса dest. Каждый процесс, включая dest, посылает содержимое своего буфера sbuf процессу dest. Собирающий процесс сохраняет данные в буфере rbuf, располагая их в порядке возрастания номеров процессов. На процессе dest существенными являются значения всех параметров, а на всех остальных процессах — только значения параметров sbuf, scount, stype, dest и comm. Значения параметров dest и comm должны быть одинаковыми у всех процессов. Параметр rcount у процесса dest обозначает число элементов типа rtype, принимаемых не от всех процессов в сумме, а от каждого процесса. С помощью похожей функции MPI_Gatherv можно принимать от процессов массивы данных различной длины.
int MPI_Scatter(void *sbuf, int scount, MPI_Datatype stype, void *rbuf, int rcount, MPI_Datatype rtype, int source, MPI_Comm comm)
• sbuf — адрес начала буфера посылки;
• scount — число элементов в посылаемом сообщении;
• stype — тип элементов отсылаемого сообщения;
• out rbuf — адрес начала буфера сборки данных;
• rcount — число элементов в принимаемом сообщении;
• rtype — тип элементов принимаемого сообщения;
• source — номер процесса, на котором происходит сборка данных;
• comm — идентификатор коммуникатора.
Функция MPI_Scatter по своему действию является обратной к MPI_Gather. Процесс source рассылает порции данных из массива sbuf всем n процессам приложения. Можно считать, что массив sbuf делится на n равных частей, состоящих из scount элементов типа stype, после чего i-я часть посылается i-му процессу. На процессе source существенными являются значения всех параметров, а на всех остальных процессах — только значения параметров rbuf, rcount, rtype, source и comm. Значения параметров source и comm должны быть одинаковыми у всех процессов. Аналогично функции MPI_Gatherv, с помощью функции MPI_Scatterv процессам можно отослать порции данных различной длины.
В следующем примере показано использование функции MPI_Scatter для рассылки строк массива. Напомним, что в языке Си, в отличие от Фортрана, массивы хранятся в памяти по строкам.
#include "mpi.h"
#include <stdio.h>
#define SIZE 4
int main(int argc, char **argv)
{
int numtasks, rank, sendcount, recvcount, source;
float sendbuf[SIZE][SIZE] = {
{1.0, 2.0, 3.0, 4.0},
{5.0, 6.0, 7.0, 8.0},
{9.0, 10.0, 11.0, 12.0},
{13.0, 14.0, 15.0, 16.0} };
float recvbuf[SIZE];
MPI_Init(&argc,&argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &numtasks);
if (numtasks == SIZE) {
source = 1;
sendcount = SIZE;
recvcount = SIZE;