Группы процессов и коммуникаторы
Управление коммуникаторами
Создание коммуникатора - коллективная операция и соответствующая подпрограмма должна вызываться всеми процессами коммуникатора. Подпрограмма MPI_Comm_dup дублирует уже существующий коммуникатор oldcomm:
int MPI_Comm_dup(MPI_Comm oldcomm, MPI_Comm *newcomm) MPI_Comm_dup(oldcomm, newcomm, ierr)
В результате вызова создается новый коммуникатор (newcomm) с той же группой процессов, с теми же атрибутами, но с другим контекстом.
Эта подпрограмма может применяться как к интра-, так и интеркоммуникаторам.
Подпрограмма MPI_Comm_create создает новый коммуникатор (newcomm) из подмножества процессов (group) другого коммуникатора (oldcomm):
int MPI_Comm_create(MPI_Comm oldcomm, MPI_Group group, MPI_Comm *newcomm) MPI_Comm_create(oldcomm, group, newcomm, ierr)
Вызов этой подпрограммы должны выполнить все процессы из старого коммуникатора, даже если они не входят в группу group, с одинаковыми аргументами.
Данная операция применяется только к интракоммуникаторам. Она позволяет выделять подмножества процессов со своими областями взаимодействия, если, например, требуется уменьшить "зернистость" параллельной программы. Побочным эффектом применения подпрограммы MPI_Comm_create является синхронизация процессов. Если, например, одновременно создаются несколько коммуникаторов, они должны создаваться в одной последовательности всеми процессами.
Пример
#include "mpi.h" #include <stdio.h> int main(int argc,char *argv[]) { char message[24]; MPI_Group MPI_GROUP_WORLD; MPI_Group group; MPI_Comm fcomm; int size, q, proc; int* process_ranks; int rank, rank_in_group; MPI_Status status; MPI_Init(&argc, &argv); MPI_Comm_size(MPI_COMM_WORLD, &size); MPI_Comm_rank(MPI_COMM_WORLD, &rank); printf("New group contains processes:"); q = size — 1; process_ranks = (int*) malloc(q*sizeof(int)); for (proc = 0; proc < q; proc++) { process_ranks[proc] = proc; printf("%i ", process_ranks[proc]); } printf("\n"); MPI_Comm_group(MPI_COMM_WORLD, &MPI_GROUP_WORLD); MPI_Group_incl(MPI_GROUP_WORLD, q, process_ranks, &group); MPI_Comm_create(MPI_COMM_WORLD, group, &fcomm); if (fcomm != MPI_COMM_NULL) { MPI_Comm_group(fcomm, &group); MPI_Comm_rank(fcomm, &rank_in_group); if (rank_in_group == 0) { strcpy(message, "Hi, Parallel Programmer!"); MPI_Bcast(&message, 25, MPI_BYTE, 0, fcomm); printf("0 send: %s\n", message); } else { MPI_Bcast(&message, 25, MPI_BYTE, 0, fcomm); printf("%i received: %s\n", rank_in_group, message); } MPI_Comm_free(&fcomm); MPI_Group_free(&group); } MPI_Finalize(); return 0; }
В следующем примере процессы разбиваются на две группы. Одна содержит процессы с чётными рангами, а другая – с нечётными.
#include "stdio.h" #include "mpi.h" void main(int argc, char *argv[]) { int num, p; int Neven, Nodd, members[6], even_rank, odd_rank; MPI_Group group_world, even_group, odd_group; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &num); MPI_Comm_size(MPI_COMM_WORLD, &p); Neven = (p + 1)/2; Nodd = p - Neven; members[0] = 2; members[1] = 0; members[2] = 4; MPI_Comm_group(MPI_COMM_WORLD, &group_world); MPI_Group_incl(group_world, Neven, members, &even_group); MPI_Group_excl(group_world, Neven, members, &odd_group); MPI_Barrier(MPI_COMM_WORLD); if(num == 0) { printf("Number of processes is %d\n", p); printf("Number of odd processes is %d\n", Nodd); printf("Number of even processes is %d\n", Neven); printf("members[0] is assigned rank %d\n", members[0]); printf("members[1] is assigned rank %d\n", members[1]); printf("members[2] is assigned rank %d\n", members[2]); printf("\n"); printf(" num even odd\n"); } MPI_Barrier(MPI_COMM_WORLD); MPI_Group_rank(even_group, &even_rank); MPI_Group_rank( odd_group, &odd_rank); printf("%8d %8d %8d\n",num, even_rank, odd_rank); MPI_Finalize(); }
Подпрограмма MPI_Comm_free помечает коммуникатор comm для удаления:
int MPI_Comm_free(MPI_Comm *comm) MPI_Comm_free(comm, ierr)
Обмены, связанные с этим коммуникатором, завершаются обычным образом, а сам коммуникатор удаляется только после того, как на него не будет активных ссылок. Данная операция может применяться к коммуникаторам обоих видов (интра- и интер-).
К числу операций управления коммуникаторами можно отнести операции MPI_Comm_size и MPI_Comm_rank. Они позволяют, в частности, распределить роли между процессами в модели master-slave.