The OpenNET Project / Index page

[ новости /+++ | форум | wiki | теги | ]

Каталог документации / Раздел "Программирование, языки" / Оглавление документа
next up previous contents
Next: Кэширование Up: Примеры интер-коммуникаторов Previous: Примеры интер-коммуникаторов   Contents

Пример 1: ``Конвейер'' из трех групп

Обмениваются группы 0 и 1, затем группы 1 и 2. Поэтому, группа 0 требует один интер-коммуникатор, группа 1 требует два интер-коммуникатора и группа 2 требует 1 интер-коммуникатор.

\includegraphics[width=4.93in,height=1.65in]{Chapter51.eps}

   main(int argc, char **argv)
   {
     MPI_Comm myComm;       /* интракоммуникатор локальной
                                 подгруппы */
     MPI_Comm myFirstComm;  /* интеркоммуникатор */
     MPI_Comm mySecondComm; /* второй интеркоммуникатор
                              (только группа 1) */
     int membershipKey;
     int rank;

     MPI_Init(&argc, &argv);
     MPI_Comm_rank(MPI_COMM_WORLD, &rank);

     /* код пользователя обязан генерировать ключ
        принадлежности в диапазоне [0, 1, 2] */
     membershipKey = rank % 3;

     /* формирование интра-коммуникатора для локальной подгруппы */

     MPI_Comm_split(MPI_COMM_WORLD, membershipKey, rank, &myComm);

     /* формирование интер-коммуникаторов
      */

     if (membershipKey == 0)
     {    /* Группа 0 связывается с группой 1 */

       MPI_Intercomm_create(myComm, 0,
           MPI_COMM_WORLD, 1, 1, &myFirstComm);
     }
     else if (membershipKey == 1)
     {    /* Группа 1 связывается с группами 0 и 2. */ 

       MPI_Intercomm_create(myComm, 0, MPI_COMM_WORLD,
           0, 1, &myFirstComm); 
       MPI_Intercomm_create(myComm, 0, MPI_COMM_WORLD,
           2, 12, &mySecondComm); 
     } 
     else if (membershipKey == 2) 
     {    /* Группа 2 связывается с группой 1. */ 

       MPI_Intercomm_create(myComm, 0, MPI_COMM_WORLD,
           1, 12, &myFirstComm); 
     } 
 
     /* рабочий участок ... */ 
 
     switch(membershipKey) /* удаление коммуникаторов
                            */ 
     { 
     case 1: 
        MPI_Comm_free(&mySecondComm); 
     case 0: 
     case 2: 
        MPI_Comm_free(&myFirstComm); 
        break; 
     } 
 
     MPI_Finalize(); 
   }

Пример 2: Кольцо из трех групп

Обмениваются группы 0 и 1, группы 1 и 2, группы 0 и 2. Следовательно, каждая группа требует два интеркоммуникатора.

   main(int argc, char **argv)
   {
     MPI_Comm myComm; /* интра-коммуникатор для локальной 
                                подгруппы */ 
     MPI_Comm myFirstComm; /* интер-коммуникатор */ 
     MPI_Comm mySecondComm; 
     MPI_Status status; 
     int membershipKey; 
     int rank; 
 
     MPI_Init(&argc, &argv); 
     MPI_Comm_rank(MPI_COMM_WORLD, &rank); 
     ... 
 
     /* код пользователя должен генерировать ключ принадлежности в
        диапазоне [0, 1, 2] */ 

     membershipKey = rank % 3; 
 
     /* формирование интра-коммуникатора для локальной подгруппы */ 
     MPI_Comm_split(MPI_COMM_WORLD, membershipKey, rank, &myComm); 
 
     /* формирование интер-коммуникаторов. */ 
     if (membershipKey == 0) 
     {       /* Группа 0 связывается с группами 1 и 2. */ 
       MPI_Intercomm_create(myComm, 0, MPI_COMM_WORLD, 1, 
           1, &myFirstComm); 
       MPI_Intercomm_create(myComm, 0, MPI_COMM_WORLD, 2, 
           2, &mySecondComm); 
     } 
     else if (membershipKey == 1) 
     {         /* Группа 1 связывается с группами 0 и 2. */ 
       MPI_Intercomm_create(myComm, 0, MPI_COMM_WORLD, 0, 
           1, &myFirstComm); 
       MPI_Intercomm_create(myComm, 0, MPI_COMM_WORLD, 2, 
           12, &mySecondComm); 
     } 
     else if (membershipKey == 2) 
     {        /* Группа 1 связывается с группами 0 и 1. */ 
       MPI_Intercomm_create(myComm, 0, MPI_COMM_WORLD, 0, 
           2, &myFirstComm);
       MPI_Intercomm_create(myComm, 0, MPI_COMM_WORLD, 1, 
           12, &mySecondComm); 
     } 
 
     /* выполнение некоторой работы ... */ 
 
     /* Теперь освобождаем коммуникаторы перед окончанием... */ 
     MPI_Comm_free(&myFirstComm); 
     MPI_Comm_free(&mySecondComm); 
     MPI_Comm_free(&myComm); 
     MPI_Finalize(); 
   }

Пример 3: Формирование службы имен для интер-коммуникации

Следующие подпрограммы показывают, как пользователь может создавать службу имен (name service) для интер-коммуникаторов на основе протокола рандеву (rendezvous) с использованием серверного коммуникатора и имени тэга, выбранного обеими группами.

После того, как все процессы MPI выполнят MPI_INIT, каждый процесс вызывает функцию Init_server(), определенную ниже. Тогда, если new_world возвращает NULL, необходим процесс, получающий NULL, чтобы осуществить функцию сервера в цикле Do_server(). Все остальные процессы делают только предписанные им вычисления, используя new_world как новый эффективный ``глобальный'' коммуникатор. Один определенный процесс вызывает Undo_Server(), чтобы избавиться от сервера, когда он больше не требуется.

Особенности этого подхода включают:

#define INIT_SERVER_TAG_1 666 
#define UNDO_SERVER_TAG_1 777 
 
static int server_key_val; 
 
/* для управления атрибутами на server_comm
   используется функция копирования: */ 
void handle_copy_fn(MPI_Comm *oldcomm, int *keyval,
      void *extra_state, void *attribute_val_in,
      void **attribute_val_out, int *flag) 
{ 
/* копирование дескриптора */ 
   *attribute_val_out = attribute_val_in; 
   *flag = 1; /* указывает, что копирование произошло */ 
} 
 
int Init_server(peer_comm, rank_of_server,
    server_comm, new_world) 
MPI_Comm peer_comm; 
int rank_of_server; 
MPI_Comm *server_comm; 
MPI_Comm *new_world; 
{ 
    MPI_Comm temp_comm, lone_comm;
    MPI_Group peer_group, temp_group; 
    int rank_in_peer_comm, size, color, key = 0; 
    int peer_leader, peer_leader_rank_in_temp_comm; 
 
    MPI_Comm_rank(peer_comm, &rank_in_peer_comm); 
    MPI_Comm_size(peer_comm, &size); 
 
    if ((size < 2)||(0 > rank_of_server)
           ||(rank_of_server >= size)) 
        return (MPI_ERR_OTHER); 
 
    /* создаются два коммуникатора путем разбиния peer_comm на
       процесс сервера и какой-либо еще */ 

        /* произвольный выбор */
    peer_leader = (rank_of_server + 1) % size;

    if ((color = (rank_in_peer_comm == rank_of_server))) 
    { 
        MPI_Comm_split(peer_comm, color, key, &lone_comm); 
 
        MPI_Intercomm_create(lone_comm, 0, peer_comm,
            peer_leader, INIT_SERVER_TAG_1, server_comm); 
 
        MPI_Comm_free(&lone_comm); 
        *new_world = MPI_COMM_NULL; 
    } 
    else 
    { 
        MPI_Comm_Split(peer_comm, color, key, &temp_comm); 
 
        MPI_Comm_group(peer_comm, &peer_group); 
        MPI_Comm_group(temp_comm, &temp_group); 
        MPI_Group_translate_ranks(peer_group, 1, &peer_leader, 
        temp_group, &peer_leader_rank_in_temp_comm); 
 
        MPI_Intercomm_create(temp_comm,
               peer_leader_rank_in_temp_comm, 
               peer_comm, rank_of_server, 
               INIT_SERVER_TAG_1, server_comm); 
 
        /* присоединяется коммуникационный атрибут new_world к
           server_comm: */

        /* КРИТИЧЕСКАЯ СЕКЦИЯ ДЛЯ MULTITHREADING */ 
        if(server_keyval == MPI_KEYVAL_INVALID) 
        { 
           /* получить локальное имя процесса для
              значения ключа сервера  */ 
            MPI_keyval_create(handle_copy_fn, NULL, 
                  &server_keyval, NULL); 
        } 

        *new_world = temp_comm; 
 
        /* кэшировать дескриптор интра-коммуникатора на 
           интер-коммуникаторе: */ 

        MPI_Attr_put(server_comm, server_keyval, (void*)
                          (*new_world)); 
    } 
 
    return (MPI_SUCCESS); 
}

Фактический процесс сервера передал бы на выполнение следующий код:

int Do_server(server_comm) 
MPI_Comm server_comm; 
{ 
    void init_queue(); 
    int en_queue(), de_queue();
        /* Сохранить триплеты целых чисел для
             последующего cравнения */ 

    MPI_Comm comm; 
    MPI_Status status; 
    int client_tag, client_source; 
    int client_rank_in_new_world,
        pairs_rank_in_new_world; 
    int buffer[10], count = 1; 
 
    void *queue;
    init_queue(&queue); 
 
    for (;;) 
    { 
        MPI_Recv(buffer, count, MPI_INT, MPI_ANY_SOURCE,
         MPI_ANY_TAG, server_comm, &status);
          /* прием от любого клиента */ 
 
        /* Определяется клиент: */ 
        client_tag = status.MPI_TAG; 
        client_source = status.MPI_SOURCE; 
        client_rank_in_new_world = buffer[0]; 
 
        if (client_tag == UNDO_SERVER_TAG_1)
         /* Клиент, который завершает работу сервера */ 
        { 
          while(de_queue(queue,MPI_ANY_TAG,
             &pairs_rank_in_new_world, &pairs_rank_in_server));
 
            MPI_Intercomm_free(&server_comm); 
            break; 
        } 
 
        if (de_queue(queue, client_tag, &pairs_rank_in_new_world, 
                &pairs_rank_in_server)) 
        { 
             /* согласованная пара с одинаковым тэгом, необходимо
                           сообщить им друг о друге! */ 
            buffer[0] = pairs_rank_in_new_world; 
            MPI_Send(buffer, 1, MPI_INT, client_src, client_tag, 
                server_comm); 
 
            buffer[0] = client_rank_in_new_world; 
            MPI_Send(buffer, 1, MPI_INT, pairs_rank_in_server,
                client_tag, server_comm); 
        } 
        else 
            en_queue(queue, client_tag, client_source, 
                client_rank_in_new_world); 
    } 
}

Особый процесс отвечает за окончание работы сервера, когда он больше не нужен, вызывая Undo_server.

int Undo_server(server_comm)
        /* пример клиента, который заканчивает
              работу сервера */ 
MPI_Comm *server_comm; 
{ 
    int buffer = 0; 
    MPI_Send(&buffer,1, MPI_INT, 0, UNDO_SERVER_TAG_1, *server_comm); 
    MPI_Intercomm_free(server_comm); 
}

Следующий код - это код блокирования сервисов имен для интер-коммуникации с теми же самыми семантическими ограничениями, как в MPI_Intercomm_create, но с упрощенным синтаксисом. Он использует функциональные возможности, определенные только для создания службы имен.

int Intercomm_name_create(local_comm, server_comm, tag, comm) 
MPI_Comm local_comm, server_comm; 
int tag; 
MPI_Comm *comm; 
{ 
    int error; 
    int found; /* получение атрибута mgmt для new_world */ 
    void *val; 
 
    MPI_Comm new_world; 
 
    int buffer[10], rank; 
    int local_leader = 0; 
 
    MPI_Attr_get(server_comm, server_keyval,
        &val, &found); 
    new_world = (MPI_Comm)val;
           /* восстановление кэшированного 
                     дескриптора */ 
 
    MPI_Comm_rank(server_comm, &rank);
            /* номер в локальной группе */ 
 
    if (rank == local_leader) 
    { 
        buffer[0] = rank; 
        MPI_Send(&buffer, 1, MPI_INT, 0, tag, server_comm); 
        MPI_Recv(&buffer, 1, MPI_INT, 0, tag, server_comm); 
    } 
 
    error = MPI_Intercomm_create(local_comm, local_leader, new_world, 
        buffer[0], tag, comm); 
 
    return(error); 
}



Alex Otwagin 2002-12-10



Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру