next up previous contents
Next: Примеры программ Up: PVM - параллельная виртуальная Previous: Распаковка данных   Contents

Динамические группы процессов

Функции динамической группировки процессов составляют основу ключевых подпрограмм PVM. Специализированная библиотека
libgpvm3 должна компоноваться с пользовательскими программами, которые используют любую групповую функцию; pvmd не реализует групповых функций. Эта задача обрабатывается групповым сервером, который запускается автоматически - при первом вызове групповой функции. Здесь приводятся некоторые сведения о том, как могут обрабатываться группы в среде с интерфейсом ``обмена сообщениями''. Выводы касаются эффективности и надежности - в данном случае найден компромисс между статическими и динамическими группами. Некоторые авторы приводят аргументы в пользу того, что только задачи из группы могут пользоваться групповыми функциями.

Согласно философии PVM групповые функции разработаны как очень обобщенные и прозрачные для пользователя, что имеет определенную цену с точки зрения эффективности. Каждая задача PVM может присоединиться или покинуть любую группу в любое время - без необходимости информирования все другие задачи затрагиваемой группы. Задачи могут широковещательно передавать сообщения в группы, членами которых они не являются. В целом, любая задача PVM может вызвать любую из следующих функций во всякое время. Исключение составляют pvm_lvgroup(), pvm_barrier() и pvm_reduce(), природа которой требует членства вызывающей задачи в указанной группе.

int inum = pvm_joingroup(char *group)

int info = pvm_lvgroup( char *group)

call pvmfjoingroup( group, inum)

call pvmflvgroup( group, info)

Эти подпрограммы позволяют задаче присоединиться к именованной пользователем группе и покинуть ее. Первый вызов
pvm_joingroup() создает группу с именем group и включает в нее вызывающую задачу; pvm_joingroup возвращает номер экземпляра процесса (inum) в некоторой группе. Номера экземпляров находятся в диапазоне от нуля до количества членов в группе - минус один. В PVM версии 3 одна задача может состоять в нескольких группах.

Если процесс покинул группу и снова пытается присоединиться к ней, то он может получить другой номер экземпляра. Номера экземпляров перераспределяются, поэтому задача, состоящая в группе, будет получать наименьший из доступных номеров экземпляров. Однако если несколько задач состоят в группе, то не гарантируется, что задаче будет ``выдан'' ее предыдущий номер экземпляра.

Чтобы помочь пользователю в управлении последовательностью назначения номеров, независимо от того, происходит присоединение или отсоединение, функция pvm_lvgroup() не завершается до тех пор, пока задача не будет достоверно извещена об этом факте; pvm_joingroup(), вызываемая после этого, назначит вакантный номер экземпляра новой задаче. Ответственность за последовательность назначения номеров экземпляров накладывается на пользователя, если в алгоритме задачи возникает потребность в этом. Если несколько задач покинет группу и в ней не останется членов, то в номерах экземпляров возникнут ``пробелы''.

int tid = pvm_gettid( char *group, int inum)

int inum = pvm_getinst( char *group, int tid)

int size = pvm_gsize( char *group)

call pvmfgettid( group, inum, tid)

call pvmfgetinst( group, tid, inum)

call pvmfgsize( group, size)

Подпрограмма pvm_gettid() возвращает TID процесса с именем группы и номером экземпляра; pvm_gettid() позволяет двум не знающим друг друга задачам получить TID друг друга посредством присоединения к общей группе. Подпрограмма pvm_getinst возвращает номер задачи с TID из указанной группы. Подпрограмма pvm_gsize возвращает количество членов в указанной группе.

int info = pvm_barrier( char *group, int count)

call pvmfbarrier( group, count, info)

Вызовом pvm_barrier() процесс блокируется до тех пор, пока count членов группы не вызовут pvm_barrier. В общем случае count должен совпадать с количеством членов в группе. Счетчик требуется потому, что при динамической группировке процессов PVM не может знать, сколько процессов имеется в группе в данный момент времени. Ошибочным действием для процесса будет вызов pvm_barrier с указанием группы, членом которой он не является. Также ошибочными, при данной барьерной синхронизации, будут вызовы с несовпадающими аргументами count. Например, ошибка возникает, если один член группы вызывает pvm_barrier() со счетчиком, равным 4, а другой член вызывает pvm_barrier со счетчиком, равным 5.

int info = pvm_bcast( char *group, int msgtag)

call pvmfbcast( group, msgtag, info)

Подпрограмма pvm_bcast() помечает сообщение целочисленным
идентификатором msgtag и широковещательно передает его всем задачам в указанной группе, за исключением ``собственной'' задачи (если она является членом группы). Для pvm_bcast() термин ``все задачи'' определяет те задачи, которые сервер группы считает находящимися в группе во время вызова подпрограммы. Если задача присоединяется к группе при широковещательном вызове, то она вообще может не получить сообщение. Если задача покидает группу при широковещательном вызове, то копия сообщения по-прежнему будет ей передаваться.

int info = pvm_reduce( void (*func()), void *data,

    int nitem, int datatype, int msgtag, char *group,

    int root)

call pvmfreduce( func, data, count, datatype, msgtag,

     group, root, info)

Подпрограмма pvm_reduce() выполняет глобальную арифметическую операцию в группе, например нахождение глобальной суммы или глобального максимума. Результат редуцирующей операции помещается в root. PVM поддерживает четыре предопределенные функции, которые пользователь может передать через func. Это функции PvmMax, PvmMin, PvmSum, PvmProduct

Редуцирующая операция над входными данными выполняется поэлементно. Например, если массив данных состоит из двух чисел с плавающей запятой, а функция - это PvmMax, то результат будет включать два числа: глобальный максимум от всех членов группы - первое - и глобальный максимум ото всех - второе.

В дополнение, пользователи могут определять свои собственные функции для глобальных операций и указывать их в func. Пример дается в исходных текстах PVM. Обратитесь к PVM_ROOT/examples/ gexamples.

Функция pvm_reduce() не блокируется. Если задача вызывает pvm_reduce, а затем покидает группу до того, как результат pvm_reduce появится в root, то может произойти ошибка.



2004-06-22