next up previous contents
Next: Функция MPI_Comm_split Up: Коммуникаторы и топологии Previous: Коммуникаторы   Contents

Работа с группами, контекстами и коммуникаторами

Для иллюстрации основ работы с коммуникаторами создается коммуникатор, основная группа которого состоит из процессов в первой строке виртуальной сетки. Пусть MPI_COMM_WORLD состоит из $p$ процессов, где $q^{2}=p$. Пусть также $\phi (x)=(x/q;xmodq)$. При этом первая строка процессов состоит из процессов с рангами $0,1,...,q-1$ (Ранги указаны относительно MPI_COMM_WORLD). Чтобы создать группу для нового коммуникатора, следует выполнить следующий код:

MPI_Group MPI_GROUP_WORLD;

MPI_Group first_row_group;

MPI_Comm first_row_comm;

int row_size;

int* process_ranks;

 

/* Создает список процессов нового */

 * коммуникатора */

process_ranks = (int*) malloc(q*sizeof(int));

for (proc = 0; proc < q; proc++) 

   process_ranks[proc] = proc;

 

/* Получить группу, относящуюся к MPI_COMM_WORLD */

MPI_Comm_group(MPI_COMM_WORLD, &MPI_GROUP_WORLD);

 

/* Создать новую группу */

MPI_Group_incl(MPI_GROUP_WORLD, q, process_ranks,

   &first_row_group); 

 

/* Создать новый коммуникатор */

MPI_Comm_create(MPI_COMM_WORLD, first_row_group,

   &first_row_comm);

Этот код строит новый коммуникатор прямым способом. Сначала он создает список процессов, которые будут помещены в новый коммуникатор. Потом он создает группу, состоящую из этих процессов, с помощью двух операций: сначала получается группа, связанная с MPI_COMM_WORLD, поскольку из этой группы будут выбраны процессы новой группы; затем создается новая группа с помощью функции MPI_Group_incl(). Наконец, фактический коммуникатор создается вызовом MPI_Comm_create(). Этот вызов также неявно ассоциирует контекст с новой группой. Результатом является коммуникатор first_row_comm. Теперь процессы в этом коммуникаторе могут выполнять коллективные действия. Например, процесс 0 может передать $A_{00}$ другим процессам в коммуникаторе:

int my_rank_in_first_row;

float* A_00;

 

/* my_rank определяет ранг процесса в MPI_GROUP_WORLD */

if (my_rank < q) {

   MPI_Comm_rank(first_row_comm, &my_rank_in_first_row);

 

   /* Выделить память для A_00, order = n_bar */

   A_00 = (float*) malloc (n_bar*n_bar*sizeof(float));

   if (my_rank_in_first_row == 0) {

      /* Инициализация A_00 */

      . . .

   }

   MPI_Bcast(A_00, n_bar*n_bar, MPI_FLOAT, 0,

      first_row_comm);

}

Группы и коммуникаторы являются непрозрачными объектами. С практической точки зрения это означает, что детали их внутреннего представления зависят от специфической реализации MPI, и как следствие пользователю нельзя непосредственно обращаться к ним. Пользователь может работать с ними через дескриптор, который ссылается на непрозрачный объект, а непрозрачные объекты управляются специальными функциями MPI, например, MPI_Comm_create(), MPI_Group_incl(), MPI_Comm_group().

Контексты явно не используются ни в одной из функций MPI. Они неявно связываются с группами при создании коммуникаторов. Операция

int MPI_Comm_group(MPI_Comm comm, MPI_Group* group)
просто возвращает группу, принадлежащую коммуникатору comm. Вторая операция:

int MPI_Group_incl(MPI_Group old_group,

    int new_group_size, int* ranks_in_old_group,

    MPI_Group* new_group)

создает новую группу из списка процессов уже существующей группы old_group. Количество процессов в новой группе равно
new_group_size, а процессы, которые будут включены в группу, перечислены в списке ranks_in_old_group. Процесс 0 в новой группе имеет ранг ranks_in_old_group[0], процесс 1 имеет ранг
ranks_in_old_group [1], и т.д. Последняя операция:

int MPI_Comm_create(MPI_Comm old_comm,

    MPI_Group new_group, MPI_Comm* new_comm)

связывает контекст с группой new_group и создает коммуникатор new_comm. Все процессы в новой группе относятся к группе, принадлежащей old_comm.

Существует важное различие между первыми двумя и третьей функциями. Вызовы MPI_Comm_group() и MPI_Group_incl() являются локальными действиями. Это значит, что нет никакого взаимодействия между процессами, участвующими в их выполнении. Операция MPI_Comm_create() - коллективное действие. Процессы в old_comm должны вызывать MPI_Comm_create() с теми же самыми аргументами.

Если создаются несколько коммуникаторов, они должны создаваться в одном и том же порядке во всех процессах.



2004-06-22