Группы процессов и коммуникаторы
Операции обмена между группами процессов
Интеробмены
При выполнении интеробмена процессу-источнику сообщения указывается ранг адресата относительно удаленной группы, а процессу-получателю — ранг источника (также относительно удаленной по отношению к получателю группы).
Обмен выполняется между лидерами обеих групп. Предполагается, что в обеих группах есть, по крайней мере, по одному процессу, который может обмениваться сообщениями со своим партнером.
Интеробмен возможен, только если создан соответствующий интеркоммуникатор, а это можно сделать с помощью подпрограммы:
int MPI_Intercomm_create(MPI_Comm local_comm, int local_leader, MPI_Comm peer_comm, int remote_leader, int tag, MPI_Comm *new_intercomm) MPI_Intercomm_create(local_comm, local_leader, peer_comm, remote_leader, tag, new_intercomm, ierr)
Входные параметры этой подпрограммы:
- local_comm - локальный интракоммуникатор;
- local_leader - ранг лидера в локальном коммуникаторе (обычно 0);
- peer_comm - удаленный коммуникатор;
- remote_leader - ранг лидера в удаленном коммуникаторе (обычно 0);
- tag - тег интеркоммуникатора, используемый лидерами обеих групп для обменов в контексте родительского коммуникатора.
Выходной параметр - интеркоммуникатор (new_intercomm).
Вызов этой подпрограммы должен выполняться в обеих группах процессов, которые должны быть связаны между собой. В каждом из этих вызовов используется локальный интракоммуникатор, соответствующий данной группе процессов.
При работе с MPI_Intercomm_create локальная и удаленная группы процессов не должны пересекаться, иначе возможны "тупики".
Пример
#include "mpi.h" #include <stdio.h> int main(int argc,char *argv[]) { int counter, message, myid, numprocs, server; int color, remote_leader_rank, i, ICTAG = 0; MPI_Status status; MPI_Comm oldcommdup, splitcomm, oldcomm, inter_comm; MPI_Init(&argc, &argv); oldcomm = MPI_COMM_WORLD; MPI_Comm_dup(oldcomm, &oldcommdup); MPI_Comm_size(oldcommdup, &numprocs); MPI_Comm_rank(oldcommdup, &myid); server = numprocs — 1; color = (myid == server); MPI_Comm_split(oldcomm, color, myid, &splitcomm); if(!color) { remote_leader_rank = server; } else { remote_leader_rank = 0; } MPI_Intercomm_create(splitcomm, 0, oldcommdup, remote_leader_rank, ICTAG, &inter_comm); MPI_Comm_free(&oldcommdup); if (myid == server) { for(i = 0; i<server; i++){ MPI_Recv(&message, 1, MPI_INT, i, MPI_ANY_TAG, inter_comm, &status); printf("Process rank %i received %i from %i\n", myid, message, status.MPI_SOURCE);} } else{ counter = myid; MPI_Send(&counter, 1, MPI_INT, 0, 0, inter_comm); printf("Process rank %i send %i\n", myid, counter); } MPI_Comm_free(&inter_comm ); MPI_Finalize(); }
В примере процессы делятся на две группы: первая состоит из одного процесса (процесс с максимальным рангом в исходном коммуникаторе MPI_COMM_WORLD), это - "сервер", а во вторую входят все остальные процессы.
Между этими группами создается интеркоммуникатор inter_comm.
Процессы-клиенты передают серверу сообщения.
Сервер принимает эти сообщения с помощью подпрограммы стандартного блокирующего двухточечного приема и выводит их на экран.
"Ненужные" коммуникаторы удаляются.