Параллельное программирование: Учебное пособие, страница 108

}

printf("\n");

   /* открываем доступ к группе, указав ее адрес */

MPI_Comm_group(MPI_COMM_WORLD, &MPI_GROUP_WORLD);

/* создаем группу сq процессами, ранги которых в process_ranks*/

MPI_Group_incl(MPI_GROUP_WORLD, q,

process_ranks, &group);

/* создаем для группы group коммуникатор с именем fcomm */

MPI_Comm_create(MPI_COMM_WORLD, group, &fcomm);

if (fcomm != MPI_COMM_NULL) /* если fcomm не пуст, то */

{  /* открываем доступ к группе и определяем ранг процесса в группе */

MPI_Comm_group(fcomm, &group);

MPI_Comm_rank(fcomm, &rank_in_group);

if (rank_in_group ==0)

{  /* печать и рассылка сообщения процессом с рангом 0 */

strcpy(message, "Hi, Parallel Programmer!");

MPI_Bcast(&message, 25, MPI_BYTE, 0, fcomm);

printf("0 send: %s\n", message);

}

else

{  /* принимаем сообщение от корневого процесса с рангом 0 */

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-программы */

MPI_Finalize();

return 0;        /* возвращаем код нормального завершения */

}

С коммуникатором MPI_COMM_WORLD может быть связано несколько процессов, например, p, которые должны быть размещены, к примеру, на 5 процессорах. Область взаимодействия организуем для q процессов. В параллельной программе сначала создается список процессов, которые будут входить в область взаимодействия нового коммуникатора. Затем создается группа, состоящая из этих процессов. Для этого требуются две операции. Первая определяет группу, связанную с коммуникатором MPI_COMM_WORLD. Новая группа создается вызовом подпрограммы MPI_Group_incl. Затем создается новый коммуникатор. Для этого используется подпрограмма MPI_Comm_create. Новому коммуникатору дается имя fcomm. В результате всех этих действий все процессы, входящие в коммуникатор fcomm, смогут выполнять операции коллективного обмена, но только между собой. Результат ее выполнения:

mpiexec –host -machinefile -n 5 – myprogr

New group contains processes:0 1 2 3

0 send: Hi, Parallel Programmer!

New group contains processes:0 1 2 3

1 received: Hi, Parallel Programmer!

New group contains processes:0 1 2 3

3 received: Hi, Parallel Programmer!

New group contains processes:0 1 2 3

2 received: Hi, Parallel Programmer!

Подпрограмма MPI_Comm_split позволяет создать несколько коммуникаторов сразу:

int MPI_Comm_split(MPI_Comm oldcomm, int split,

int rank, MPI_Comm* newcomm)

Группа процессов, связанных с коммуникатором oldcomm, разбивается на непересекающиеся подгруппы, по одной для каждого значения аргумента split. Процессы с одинаковым значением split образуют новую группу. Ранг в новой группе определяется значением rank. Если процессы А и В вызывают MPI_Comm_split с одинаковым значением split, а аргумент rank, переданный процессом А, меньше, чем аргумент, переданный процессом В, то ранг процесса А в группе, соответствующей новому коммуникатору, будет меньше ранга процесса В. Если же в вызовах используется одинаковое значение rank, то система присвоит ранги произвольно. Для каждой подгруппы создается собственный коммуникатор newcomm.

MPI_Comm_split — коллективная подпрограмма, ее должны вызвать все процессы из старого коммуникатора, даже если они и не войдут в новый коммуникатор. Для этого в качестве аргумента split в подпрограмму передается предопределенная константа MPI_UNDEFINED. Соответствующие процессы вернут в качестве нового коммуникатора значение MPI_COMM_NULL. Новые коммуникаторы, созданные подпрограммой MPI_Comm_split, не пересекаются, однако с помощью повторных вызовов подпрограммы MPI_Comm_split можно создавать и перекрывающиеся коммуникаторы.

Пример расщепления коммуникатора:

MPI_Comm_rank(MPI_Commcomm, intrank)

MPI_Comm_size(MPI_Comm comm, int size)

split = 2*rank/size

key = size - rank - 1

MPI_Comm_split(MPI_Comm comm, int split,