Санкт-Петербургский государственный университет
Опубликован: 11.10.2012 | Доступ: свободный | Студентов: 955 / 173 | Длительность: 05:14:00
Лекция 6:

Группы процессов и коммуникаторы

< Лекция 5 || Лекция 6: 1234 || Лекция 7 >

Управление коммуникаторами

Создание коммуникатора - коллективная операция и соответствующая подпрограмма должна вызываться всеми процессами коммуникатора. Подпрограмма 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.

< Лекция 5 || Лекция 6: 1234 || Лекция 7 >