Charles is exactly right; intercommunicators allow you to talk between communicators (or, to distinguish between “normal” communicators in this context, “intra-communicators”, which does not affect me as an improvement).
. , , , () MPI_Reduce . , , , ; , , MPI_PROC_NULL root, MPI_ROOT. , ?
#include <mpi.h>
#include <stdio.h>
int main(int argc, char **argv)
{
int commnum = 0;
MPI_Comm mycomm;
MPI_Comm intercomm;
int cw_rank, cw_size;
int rank;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &cw_rank);
MPI_Comm_size(MPI_COMM_WORLD, &cw_size);
if (cw_rank == cw_size-1)
commnum = 2;
else {
if (cw_rank < (cw_size-1)/2)
commnum = 0;
else
commnum = 1;
}
printf("Rank %d in comm %d\n", cw_rank, commnum);
MPI_Comm_split(MPI_COMM_WORLD, commnum, cw_rank, &mycomm);
const int lldr_tag = 1;
const int intercomm_tag = 2;
if (commnum == 0) {
int local_leader = 0;
MPI_Comm_rank(mycomm, &rank);
if (rank == 0)
MPI_Send(&cw_rank, 1, MPI_INT, cw_size-1, 1, MPI_COMM_WORLD);
MPI_Intercomm_create( mycomm, local_leader,
MPI_COMM_WORLD, cw_size-1,
intercomm_tag, &intercomm);
}
else if (commnum == 2)
{
int local_leader = 0;
int rmt_ldr;
MPI_Status s;
MPI_Recv(&rmt_ldr, 1, MPI_INT, MPI_ANY_SOURCE, lldr_tag, MPI_COMM_WORLD, &s);
MPI_Intercomm_create( mycomm, local_leader,
MPI_COMM_WORLD, rmt_ldr,
intercomm_tag, &intercomm);
}
if (commnum == 0) {
int max_of_ranks = 0;
MPI_Reduce(&rank, &max_of_ranks, 1, MPI_INT, MPI_MAX, 0, mycomm);
if (rank == 0) {
printf("Within comm 0: maximum of ranks is %d\n", max_of_ranks);
printf("Within comm 0: sum of ranks should be %d\n", max_of_ranks*(max_of_ranks+1)/2);
}
MPI_Reduce(&rank, &max_of_ranks, 1, MPI_INT, MPI_SUM, 0, intercomm);
}
if (commnum == 2) {
int sum_of_ranks = -999;
int rootproc;
if (rank == 0)
rootproc = MPI_ROOT;
else
rootproc = MPI_PROC_NULL;
MPI_Reduce(&rank, &sum_of_ranks, 1, MPI_INT, MPI_SUM, rootproc, intercomm);
if (rank == 0)
printf("From comm 2: sum of ranks is %d\n", sum_of_ranks);
}
if (commnum == 0 || commnum == 2);
MPI_Comm_free(&intercomm);
MPI_Finalize();
}