close

Вход

Забыли?

вход по аккаунту

?

DCOM

код для вставкиСкачать
№ 0000
МИНИСТЕРСТВО ОБРАЗОВАНИЯ
РОССИЙСКОЙ ФЕДЕРАЦИИ
ТАГАНРОГСКИЙ ГОСУДАРСТВЕННЫЙ
РАДИОТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ
РУКОВОДСТВО
к выполнению лабораторной работы
ПАРАЛЛЕЛЬНЫЕ ВЫЧИСЛЕНИЯ НА СЕТЕВЫХ КЛАСТЕРАХ С ПОМОЩЬЮ ТЕХНОЛОГИИ DCOM И VISUAL C++.NET
по курсу
ПАРАЛЛЕЛЬНОЕ ПРОГРАММИРОВАНИЕ
Для студентов специальностей 220400, 351500 и магистрантов направления 552800
Таганрог 2004
УДК 681.324 (076)
Составители Р.В.Троценко, А.Г.Чефранов, П.А.Беспалов
Руководство к лабораторной работе "Параллельные вычисления на сетевых кластерах с помощью технологии DCOM и Visual C++.NET" по курсу "Параллельное программирование". Таганрог: Изд-во ТРТУ, 2004. 37 с.
Руководство предназначено для студентов специальностей 2204, 3515 и магистрантов направления "Информатика и вычислительная техника", изучающих курс "Параллельное программирование". Содержит краткие сведения о технологиях COM и DCOM, описание настройки операционной системы для работы с DCOM-приложениями, а также порядка разработки распределенных DCOM-приложений в среде Visual C++.NET. Приведен подробный пример создания распределенного приложения, перечень заданий и требования к отчету.
Ил. 10. Библиогр.: 7 назв.
Рецензент Н.Ш.Хусаинов, к.т.н., доцент кафедры МОП ЭВМ ТРТУ.
ВВЕДЕНИЕ
Технология Distributed Component Object Model (DCOM) - распределенная компонентная модель - впервые была реализована летом 1996 года в операционной системе Microsoft Windows NT в качестве расширения компонентной объектной модели (COM). Соответственно, многое из того, что можно сказать о COM будет справедливо и для DCOM. Основным отличием DCOM является реализация технологии COM для удаленных процессов, в т.ч. и в сетевой среде, что позволяет использовать DCOM при проведении распределенных вычислений.
Основной целью этой работы является освоение технологии DCOM для ее применения при построении распределенных вычислительных систем, а также использования при решении задач, для которых возможно распараллеливание вычислений. В руководстве приведено описание технологий COM и DCOM для построения распределенных приложений в среде Visual C++.NET под платформу MS Win32.
1. ЦЕЛЬ РАБОТЫ
Целью настоящей работы является освоение технологии DCOM в среде разработки Visual C++.NET и исследование способов создания распределенных приложений на основе нескольких компьютеров, соединенных локальной сетью, что дает реальную возможность параллельной обработки данных в распределенной вычислительной системе.
2. ОСНОВНЫЕ ТЕОРЕТИЧЕСКИЕ СВЕДЕНИЯ
2.1. Технология COM
Понимание DCOM сложно без изучения базы, на которой она построена - технологии COM. Подробное рассмотрение COM выходит за рамки данного руководства и может быть найдено в [1,2], здесь приведены только основные сведения.
В основу COM легли принципы клиент-серверного взаимодействия и объектно-ориентированного программирования. Сервером в данном случае является объект, обладающий определенным набором методов. Обращение к методам объекта (сервера) осуществляет приложение-клиент, которое обычно (но не обязательно!) имеет представление о структуре объекта.
Одним из основных положений COM является разделение описания объекта (иначе объекты могут называться компонентами) и его реализации. В связи с этим введены понятия интерфейса (interface) и сокласса (coclass). Интерфейс лишь описывает структуру объекта аналогично тому, как это делается в .h файлах языка C++, и не содержит реализации указанных в нем методов. По сути дела под интерфейсом можно понимать обычный класс языка C++, все методы которого являются абстрактными (не имеющими реализации). Сокласс наследуется от одного или нескольких интерфейсов и содержит реализацию методов с помощью конкретного языка программирования. Все методы, описанные в интерфейсе, являются виртуальными, что не позволяет запутаться в сложной иерархии интерфейсов при вызове методов.
Клиентская программа, как правило, имеет доступ только к описанию интерфейсов объектов, а также обладает информацией об уникальных идентификаторах соклассов, реализующих нужные ей интерфейсы. Она абсолютно не осведомлена о деталях реализации того или иного метода определенного класса, что позволяет свободно менять реализацию методов при условии, что не меняются интерфейсы, которые ссылаются на модифицированные методы. Такой подход чрезвычайно удобен, т.к. позволяет исправлять допущенные ранее ошибки реализации при условии неизменности интерфейсов. Подобные исправления не требуют повторной перекомпиляции программ-клиентов, использующих подвергшиеся изменению объекты.
Таким образом, COM декларирует, что реализация методов объектов может меняться как угодно при условии неизменности интерфейсов данных объектов. Если необходимо внести изменения в сам интерфейс, то создается новый интерфейс (с новым именем и идентификатором) на базе прежнего, содержащий необходимые изменения, т.е. однажды запущенный в свободное обращение интерфейс не должен быть модифицирован.
Корпорация Microsoft определила несколько базовых интерфейсов, которые широко используются при создании собственных COM-объектов. Вкратце рассмотрим основные из них.
Интерфейс IUnknown является базовым для всех остальных интерфейсов, т.е. любой COM-интерфейс всегда содержит в качестве своего первого родителя IUnknown. IUnknown содержит методы (без реализации!) для получения ссылок на другие интерфейсы и обеспечения жизненного цикла объекта, в т.ч. автоматического уничтожения объекта, у которого отсутствуют подключения клиентов.
Интерфейс IClassFactory облегчает создание COM-объектов. По ссылке на идентификаторы класса и интерфейса фабрика классов возвращает указатель на объект.
Интерфейс IDispatch используется в том случае, когда клиент не располагает сведениями о структуре COM-объекта. Этот интерфейс позволяет получить информацию о поддерживаемых объектом методах, их параметрах. Также можно осуществить вызов необходимого метода COM-объекта.
Интерфейс IMarshall применяется при связывании клиента и сервера, находящихся в разных процессах, как в пределах одной машины, так и на разных машинах в сети. Этот процесс называется маршаллингом.
Для описания собственных интерфейсов как правило используется язык IDL (interface definition language), который по своему синтаксису напоминает С++.
Существуют два основных типа COM-объектов:
1. COM-объект работающий в пространстве клиента
2. COM-объект работающий в пространстве другого процесса
Первый вариант представлен DLL-серверами, которые подключаются к клиенту при его обращении к COM-объекту и работают в том же адресном пространстве, что и клиент.
Второй вариант реализуется EXE-серверами, которые являются отдельными процессами, работающими в своем собственном адресном пространстве. В этом случае используется специальный механизм маршаллинга, позволяющий преодолеть межпроцессный барьер.
Следует отметить, что один COM-сервер может содержать в себе несколько COM-объектов.
2.2. Особенности технологии DCOM
Рассмотрим, что происходит, когда клиент и сервер находятся на разных машинах сети или на одной машине, но в разных процессах (по сути дела, на разных виртуальных машинах). Рис. 2. Связь клиента и COM-компонента на различных машинах [3]
На рис. 1 приведена иллюстрация, показывающая такую ситуацию. В этом случае на стороне клиента и сервера создаются их представители, которые называются proxy (прокси) для клиента и stub (заглушка) - для сервера. Клиент вызывает метод сервера, обращаясь к его представителю - proxy, который принимает параметры вызова, упаковывает их для передачи с помощью DCE RPC (Distributed Computing Environment Remote Procedure Call) и отправляет серверу. На серверной стороне параметры принимаются заглушкой stub, представляющей клиента, распаковываются и действительно передаются вызываемому методу сервера, после обработки запроса его результаты в обратном порядке доставляются клиенту.
Следует отметить, что DCOM-объекты могут включаться как в DLL-сервера, так и EXE-сервера. В случае DLL используются специальные суррогатные процессы, которые при вызове объекта подключают к себе реализующую его DLL и транслируют ей запросы.
Выделим ряд отличительных черт DCOM.
1. Языки и местоположение кода
Для создания DСОМ - компонентов может использоваться любой язык, и эти компоненты могут использоваться большим числом языков и инструментов. Java, Microsoft Visual C++, Microsoft Visual Basic, и Delphi - все они хорошо взаимодействуют с DCOM. При программировании практически не учитывается местоположение кода в сети.
2. Безопасность
DCOM может обеспечить безопасность распределенному приложению без встраивания специализированного кодирования безопасности в клиент или объект. Модель программирования DCOM скрывает потребность в безопасности со стороны компонента. Тот же двоичный код, который работает на одной машине, где безопасность - не главное требование, может использоваться и в распределенном приложении с обеспечением защищенности [4].
DCOM достигает подобной прозрачности в безопасности, позволяя разработчикам и администраторам конфигурировать установки защищенности для каждого компонента. DCOM содержит списки управления доступом для компонентов. Эти списки показывают, какие пользователи или группы пользователей имеют право доступа к компонентам определенного класса. Эти списки могут легко конфигурироваться инструментом конфигурирования DCOM (DCOMCNFG) или программироваться с помощью реестра Windows NT и функций обеспечения безопасности Win32.
Когда бы клиент ни вызвал метод или создал экземпляр компонента, DCOM получает текущее пользовательское имя клиента, связанного с текущим процессом. Windows NT гарантирует, что данный пользовательский идентификатор аутентичен. После этого DCOM передает имя пользователя машине или процессу, где работает этот компонент. На машине компонента DCOM снова проверяет имя пользователя, используя аутентификационный механизм, и проверяет список управления доступом для данного компонента. Если на каком-то этапе нарушаются политики безопасности, происходит отказ в доступе.
2.3. Основные принципы построения распределенных приложений
Наилучшим образом для произведения параллельных вычислений с помощью DCOM подходит идеология SPMD. Клиенты играют роль вычислительных элементов, а сервер - роль центрального управляющего элемента, распределяющего данные и собирающего результаты. Также может быть введен еще один тип клиента, предназначенный для отображения текущего состояния вычислений и вывода результатов работы на экран.
3. ПРИМЕР ВЫПОЛНЕНИЯ РАБОТЫ В СРЕДЕ VISUAL C++.NET
3.1. Начальные сведения
Задача-пример формулируется следующим образом: необходимо реализовать параллельное вычисление длины вектора из N элементов.
В случае использования среды разработки Visual C++ [1] возможны два основных варианта создания COM-объектов:
1. Создание интерфейсов и объектов вручную, в т.ч. с использованием IDL
2. Использование библиотеки ATL (active template library)
В данном руководстве будет применен второй вариант, т.к. он значительно упрощает и ускоряет создание полноценных COM-объектов и приложений-клиентов, а также обладает мощной поддержкой со стороны мастеров среды разработки.
3.2. Разработка структуры приложения
Формула вычисления длины вектора X, состоящего из N элементов выглядит так:
Очевидно, что стоящую под знаком корня сумму квадратов элементов вектора можно вычислить параллельно, разбив на непересекающиеся части.
Таким образом, структура приложения может выглядеть так: единственный сервер занимается раздачей подключившимся к нему клиентам непересекающихся частей вектора X, а затем сбором частичных сумм, их итоговым суммированием и извлечением корня; многочисленные клиенты проводят поиск частичных сумм каждый для своего подвектора вектора X и возвращают результат серверу.
Также пусть в системе будет еще один клиент, который займется вводом и передачей серверу исходных данных, контролем процесса вычислений и выводом результата на экран. Для реализации интерфейса с COM-сервером в него будет добавлен COM-объект управления.
Отметим, что вполне допустимо эти функции полностью оставить программе-серверу, что несколько упростит его как его структуру, так и структуру параллельной программы в целом, исключив из них клиент и COM-объект управления. В данном примере реализация отдельного управляющего клиента продиктована желанием использовать по максимуму возможности среды разработки, автоматизирующие труд программиста.
3.3. Предварительные действия
Первым делом необходимо создать макет проекта в среде разработки. Для этого выбираем пункт меню File/New project. В качестве типа проекта (список Project types) будет Visual C++ Projects, мастер должен быть ATL Project (рис. 2).
В качестве имени проекта укажем vect_len_p. Директорию расположения проекта можно выбрать по своему усмотрению в поле Location. После нажатия OK требуется изменить настройки мастера так, как это показано на рис. 3. В этом случае мы говорим, что наш объект будет представлять из себя EXE-сервер, т.е. наиболее удачный вариант для DCOM.
Рис. 2. Меню File/New Project
Реально эти действия приведут к добавлению двух проектов: один под названием vect_len_p, содержащий COM-сервер; второй с именем vect_len_pPS реализует прокси объекта в виде DLL, которую необходимо будет разместить и зарегистрировать на каждой клиентской машине. Код первого проекта требует изменений по мере наращивания функциональности COM-сервера. Код второго проекта не нуждается в коррекции, он будет модифицироваться по мере необходимости самой средой разработки.
Рис. 3. Форма настроек мастера
3.4. Создание серверной части
Как было сказано выше, один COM-сервер будет реализовывать два COM-объекта: объект вычислений и объект управления.
Добавим описание COM-объекта вычислений. Для этого в окне Solution Explorer необходимо щелкнуть правой кнопкой мыши на название проекта vect_len_p и выбрать пункт контекстного меню Add/Add Class. Такая последовательность действий приведет к появлению окна, показанного на рис. 4.
Нажав Open, попадаем в окно настроек класса, имеющее два пункта (рис. 5,6)
В пункте Names выбираются имена для класса С++ (Class), файлов описания и реализации, сокласса (Coclass), интерфейса (Interface), описания объекта в реестре (Type), имени, используемом при порождении объекта вместо уникального идентификатора (ProgID). Среде достаточно только параметра Short name, остальные поля будут заполнены автоматически.
Рис. 4. Добавление нового класса ATL
Рис. 5. Окно настроек объекта, пункт Names
Рис. 6. Окно настроек объекта, пункт Options
Пункт Options содержит ряд важных параметров создаваемого объекта. Прежде всего, для нас важен параметр Threading Model, его мы рассмотрим подробнее. Apartment и Single являются однотипными моделями и подразумевают, что объект всегда обрабатывает запросы от клиентов в одном потоке. Free позволяет обрабатывать запросы от клиентов в разных потоках. В этом случае необходимо обеспечить синхронизацию данных, но в то же время достигается полностью параллельная обработка запросов.. Both - может быть использована как модель Free, так и модель Apartment в зависимости от типа клиентского приложения. Выберем модель Free.
Параметр Interface позволяет включить поддержку интерфейса IDispatch (вариант Dual) или отключить ее (вариант Custom). Соответственно, это добавит или уберет поддержку автоматизации.
После нажатия клавиши OK в проект COM-сервера будут добавлены файлы описания интерфейса и реализации нового объекта: VectLenSrv.h и VectLenSrv.cpp.
Далее требуется создать описания и реализации методов объекта. Для этого необходимо в окне проекта выбрать закладку Class View и в ней щелкнуть правой кнопкой мыши на название интерфейса IVectLenSrv, выбрав при этом Add/Add Method, что повлечет за собой открытие диалога добавления метода (рис. 7).
Рис. 7. Окно добавления метода
В этом окне требуется заполнить поле Method Name (имя метода) и добавить параметры метода, указав их тип и атрибут. Атрибут in означает, что метод является входным, атрибут out - выходным, атрибут retval означает, что этот параметр примет значение возвращаемое методом.
Описание методов и их назначения приведено в таблице 1.
Таблица 1. Методы объекта-вычислителя
Имя методаПараметрыНазначениеGetData[out] VARIANT* vrData, [out] LONG* lReasonЭтот метод возвращает клиентской программе данные, с которыми она будет работать, и код состояния, который определяет ее дальнейшие действия.SetData[in] FLOAT flPartSumС помощью этого метода клиент возвращает частичную сумму серверу После того, как описания и реализации методов добавлены и класс CVectLenSrv модифицирован соответствующим образом можно считать, что создание COM-объекта вычислений завершено и теперь необходимо создать COM-объект управления.
Объект управления создается аналогично. Пусть его имя будет CtrlSrv. Его добавление создаст еще два файла по аналогии с объектом вычислений. Методы объекта управления, которые необходимо добавить, описаны в таблице 2.
Таблица 2. Методы объекта управления
Имя методаПараметрыНазначениеStartCalc[in] VARIANT vrDataМетод инициирует процесс вычислений, одновременно поставляя исходные данные в виде вариантного массива.IsWorking[out] LONG* lWorkingМетод возвращает в выходном параметре истину, если вычисления уже идут и ложь - в противном случае.GetResult[out] FLOAT* fResultВозврат результата вычислений, если они окончены.GetClientCnt[out] LONG* lClntCntВозврат количества подключенных вычисляющих клиентов. На данном этапе создание скелета COM-сервера завершено и осталось произвести наполнение описаний методов, созданных оболочкой, кодом, как показано в листинге, который будет приведен ниже. Далее необходимо перейти к созданию клиентских приложений.
3.5. Создание клиентского приложения
Клиентское приложение DCOM практически по сути дела мало отличается от обычной программы на C++. Это может быть как консольное приложение, так и приложение Windows с графическим интерфейсом. Отличие состоит лишь в том, что клиентское приложение должно инициализировать подсистему COM и получить указатель на интересующий ее интерфейс COM-объекта.
Инициализация COM выполняется функцией:
HRESULT CoInitialize(LPVOID pvReserved)
Единственный параметр данной функции должен всегда быть NULL. Кроме того, необходимо отметить, что большинство COM-функций возвращают в качестве своего результата значение типа HRESULT, содержащая информацию о результатах вызова. Проверить, была ли ошибка можно с помощью макроса FAILED(HRESULT rcode), который возвращает ненулевое значение, если ошибка имела место и нулевое - в противном случае.
После того, как программа поработала с COM, следует деинициализировать COM-подсистему:
void CoUninitialize(void)
Получить указатель на интересующий DCOM-интерфейс можно с помощью кода:
COSERVERINFO sinfo;//Служебная структура
sinfo.dwReserved1=sinfo.dwReserved2=0;
//Адрес сервера в виде Unicode-строки:
sinfo.pwszName=L"127.0.0.1";
sinfo.pAuthInfo=NULL;
<Имя интерфейса объекта> *pObj;
MULTI_QI qi={&IID_<Имя интерфейса объекта>,NULL,0};
if(FAILED(CoCreateInstanceEx(<Имя класса объекта>, NULL,CLSCTX_REMOTE_SERVER,&sinfo,1,&qi)))
//Произошла ошибка подключения
else
{
//Подключение прошло успешно
pObj=(<Имя интерфейса объекта*)qi.pItf;
}
По окончание работы с объектом, необходимо освободить его вызовом:
<Имя интерфейса объекта>->Release()
Соответственно, все последующие обращения к методам объекта производятся с использованием полученного через функцию CoCreateInstanceEx указателя на интерфейс.
Чтобы получить доступ к описаниям интерфейсов COM-сервера, необходимо подключить tlb-файл, находящийся в директории с проектом сервера:
#import "путь к файлу\имя файла.tlb" no_namespace named_guids
3.6. Рекомендации по настройке клиента и сервера DCOM
Для установки удаленного соединения с сервером необходимо произвести настройку на стороне сервера и клиента. На компьютерах, где будут установлены клиенты и COM-сервер, необходимо зарегистрировать прокси объекта, для чего используется программа regsvr32.exe, входящая в комплект поставки Windows. Делается это следующим образом:
Regsrv32.exe <путь к DLL-файлу прокси соответствующего COM-объекта>
Напомним, что DLL-файл прокси создается автоматически в процессе работы над проектом COM-объекта. Соответственно, остается только перенести его на каждую из клиентских машин и зарегистрировать по определенному пути.
Серверная машина также должна иметь дополнительную информацию о COM-сервере, для чего требуется запустить программу COM-сервера с ключом /regserver.
При регистрации в реестре создаются ключи идентифицирующие COM-объект и прокси. Для успешной регистрации необходимо иметь доступ на запись к ряду разделов реестра Windows:
HKEY_CLASSES_ROOT
HKEY_CLASSES_ROOT\CLSID
HKEY_CLASSES_ROOT\Interface
HKEY_LOCAL_MACHINE\Software\Classes
HKEY_LOCAL_MACHINE\Software\Classes\CLSID
HKEY_LOCAL_MACHINE\Software\Classes\Interface
Серверная машина должна быть особым образом настроена с использованием средств операционной системы. Приведенная ниже информация по настройке DCOM-соединения ориентирована на Windows NT 4.0/2000. Windows XP обладает похожими настроечными способностями и отличается в основном интерфейсом апплетов настройки. Поэтому можно сказать, что по большей части нижеизложенное корректно и для данной операционной системы.
Для настройки DCOM-соединения пользователь должен принадлежать к группе Администраторы на данном компьютере. Поддержка DCOM встроена в операционную систему.
Рис. 8. Определение полномочий DCOM
Настройка серверной части производится с помощью утилиты dcomcnfg.exe (рис. 8). В ней необходимо установить флажок, разрешающий использование DCOM на компьютере.
Далее найти имя класса на вкладке "Приложения" и нажать кнопку "Свойства", при этом откроется окно, позволяющее настроить параметры запуска и безопасности для серверного приложения.
Операционная система позволяет настроить уровень проверки подлинности клиента одним из следующих способов:
* подключение (Connect) - при соединении;
* нет (None) - отсутствует.
* пакеты (Packet) - проверка подлинности каждого полученного пакета данных;
* по умолчанию (Default) - используется "Подключение";
* вызов (Call) - аутентификация клиента при каждом удаленном вызове процедуры;
* целостность пакетов (Integrity) - проверка того, что данные, пересланные клиентом, не были изменены;
* секретность пакетов (Privacy) - шифрование идентификатора клиента и всех параметров вызова удаленной процедуры.
При типовой настройке сервера может использоваться следующая конфигурация [5]:
* на вкладке "Учетная запись" выбирается значение "Указанный пользователь" и вводятся идентификатор и пароль пользователя, имеющего достаточные права для доступа к необходимым ресурсам (например, файлам на NTFS);
* на вкладке "Общие" выбирается уровень проверки пользователя "Подключение" (Connect);
* на вкладке "Безопасность" в "Пользовательские разрешения" доступа и запуска добавляется идентификатор "Все пользователи".
Для определения полномочий, предоставляемых клиентом серверу, используется уровень олицетворения. B Windows NT он принимает следующие значения [5]:
* определить (Identify) - сервер при соединении получает данные о клиенте;
* олицетворить (Impersonate) - сервер может выполнять задачи от имени клиента только на компьютере сервера.
* аноним (Anonymous) - сервер не идентифицирует клиента;
* делегировать (Delegate) - сервер может выполнять задачи от имени клиента не только на своем но и на других компьютерах сети.
Также допустимо настраивать контекст пользователя, с которым будет работать сервер:
* взаимодействующий пользователь - вошедший в систему интерактивно, если пользователь не вошел в систему, приложение не будет исполняться;
* запускающий пользователь - пользователь, запустивший приложение;
* указанный пользователь - необходимо выбрать пользователя и ввести пароль для входа в систему, при этом уровень проверки подлинности клиента не может быть "нет".
3.7. Программная реализация
Программа состоит из нескольких модулей: COM-сервер (включая проект прокси), вычисляющий клиент, контролирующий клиент. Причем, как уже говорилось ранее, COM-сервер содержит два объекта: вычислений и контроля.
Рассмотрим подробнее каждый из модулей.
3.7.1 Программная реализация COM-объекта вычислений
Объект вычислений при подключении к нему вычисляющих клиентов подсчитывает их количество. Далее клиенты блокируется на вызове метода GetData и снова стартуют только после того, как объект контроля отдаст соответствующую команду. После старта объект-вычислитель раздает клиентам непересекающиеся порции информации. Клиенты их обрабатывают и вызовом метода SetData возвращают объекту результат. Листинг объекта вычислений приведен ниже.
VectLenSrv.h
#pragma once
#include "resource.h" // main symbols
extern long g_lClnCnt;
extern CRITICAL_SECTION g_csData;
[
object,
uuid("185D516A-2A12-4BFB-BFFC-193D19785D37"),
helpstring("IVectLenSrv Interface"),
pointer_default(unique)
]
__interface IVectLenSrv : IUnknown
{
[helpstring("method GetData")] HRESULT GetData([out] VARIANT* vrData, [out] LONG* lReason);
[helpstring("method SetData")] HRESULT SetData([in] FLOAT flPartSum);
};
[
coclass,
threading("free"),
vi_progid("vect_len_p.VectLenSrv"),
progid("vect_len_p.VectLenSrv.1"),
version(1.0),
uuid("195326C6-7C25-494B-B80B-1F8726FE83F5"),
helpstring("VectLenSrv Class")
]
class ATL_NO_VTABLE CVectLenSrv : public IVectLenSrv
{
public:
CVectLenSrv()
{
}
DECLARE_PROTECT_FINAL_CONSTRUCT()
HRESULT FinalConstruct()
{
EnterCriticalSection(&g_csData);
g_lClnCnt++;//Увеличение количества подключенных клиентов
LeaveCriticalSection(&g_csData);
return S_OK;
}
void FinalRelease() {
EnterCriticalSection(&g_csData);
g_lClnCnt--;//Уменьшение количества подключенных клиентов
LeaveCriticalSection(&g_csData);
}
public:
STDMETHOD(GetData)(VARIANT* vrData, LONG* lReason);
STDMETHOD(SetData)(FLOAT flPartSum);
};
VectLenSrv.cpp
#include "stdafx.h"
#include "VectLenSrv.h"
#include "math.h"
VARIANT g_vtData;//Данные для программ расчета
long g_lClnCnt=0;//Счетчик подключенных клиентов
long g_lGDClnCnt=0;//Счетчик клиентов, которые должны получить данные
long g_lSDClnCnt=0;//Счетчик клиентов, которые должны вернуть результат
int g_iCurSlice=0;//Количество элементов, которые получает один клиент
int g_iElemCnt=0;//Общее количество элементов в векторе
float g_flSum=0;//Итоговая сумма
bool bStarted=false;//Флаг-указатель, что вычисления уже начались
//Критическая секция защиты от одновременного доступа к разделяемым данным
CRITICAL_SECTION g_csData;
HANDLE g_stEvent;//Событие начала работы программы
STDMETHODIMP CVectLenSrv::GetData(VARIANT* vrData, LONG* lReason)
{
//Получение своей порции информации очередным клиентом:
WaitForSingleObject(g_stEvent,INFINITE);//ожидаем старта вычислений
EnterCriticalSection(&g_csData);
*lReason=0;
if(g_lGDClnCnt>=0)
{
//Выдаем порцию информации:
int iStElem,iElCnt;
iStElem=g_lGDClnCnt*g_iCurSlice;
g_lGDClnCnt--;//Уменьшаем на 1 кол-во клиентов, получивших информацию
//Поиск количества элементов, которое уйдет очередному клиенту:
iElCnt=(iStElem+g_iCurSlice>g_iElemCnt)?(g_iElemCnt-iStElem): g_iCurSlice;
if(iElCnt>0)
{
//Создаем вариантный массив:
SAFEARRAYBOUND sab;
sab.cElements=iElCnt;sab.lLbound=0;
HRESULT hr;
SAFEARRAY * pSa;
pSa = SafeArrayCreateEx(VT_R4,1,&sab,NULL);
//Удалось ли создать массив:
if (pSa==NULL) MessageBox(NULL,"Error 0","",0);
PVOID pvData,pvSData;
//Получение доступа к данным созданного массива:
hr=SafeArrayAccessData(pSa,&pvData);
if (FAILED(hr)) {SafeArrayDestroy(pSa);
MessageBox(NULL,"Error 1","",0);}
//Доступ к массиву, содержащему вектор:
hr=SafeArrayAccessData(V_ARRAY(&g_vtData),&pvSData);
if (FAILED(hr)) {MessageBox(NULL,"Error 2","",0);}
float *pvFl,*pvSFl;
pvFl=(float *)pvData;
pvSFl=(float *)pvSData;
//Копирование части одного массива в другой:
CopyMemory(pvFl,pvSFl+iStElem,sizeof(float)*iElCnt);
hr = SafeArrayUnaccessData(pSa);
if (FAILED(hr)) {SafeArrayDestroy(pSa);
MessageBox(NULL,"Error 3","",0);}
hr = SafeArrayUnaccessData(V_ARRAY(&g_vtData));
if (FAILED(hr)) {MessageBox(NULL,"Error 4","",0);}
VariantInit(vrData);//Инициализация возвращаемого значений
V_VT(vrData)=VT_ARRAY|VT_R4;//Задаем тип вариантной переменной
V_ARRAY(vrData)=pSa;//Присваиваем данные
}
else
{
*lReason=1;//Признак того, что данных этому клиенту не досталось
//Уменьшаем количество клиентов, которые будут возвращать результат:
g_lSDClnCnt--;
}
}
LeaveCriticalSection(&g_csData);
return S_OK;
}
STDMETHODIMP CVectLenSrv::SetData(FLOAT flPartSum)
{
//Получение частичной суммы:
EnterCriticalSection(&g_csData);
if(!g_lSDClnCnt) {
LeaveCriticalSection(&g_csData);
return E_FAIL;
}
g_flSum+=flPartSum;
g_lSDClnCnt--;//Уменьшаем количество клиентов, вернувших результат
if(!g_lSDClnCnt)//Все клиенты вернули результат
{
//Это окончание вычислений:
g_flSum=sqrt(g_flSum);//Извлечение корня - последний штрих
bStarted=false;//Вычисления окончены
}
LeaveCriticalSection(&g_csData);
return S_OK;
}
3.7.2 Программная реализация COM-объекта контроля
Этот COM-объект предназначен для мониторинга и управления COM-объектом вычислений. Он передает стартовые данные и запускает сам процесс вычислений. Через него можно получить доступ к результатам вычислений, а также к некоторым данным о состоянии объекта вычислений.
Ниже приведен листинг COM-объекта контроля.
CtrlSrv.h
#pragma once
#include "resource.h" // main symbols
[
object,
uuid("C1294BB2-78A9-41b9-9EFD-273D83FAA467"),
helpstring("ICtrlSrv Interface"),
pointer_default(unique)
]
__interface ICtrlSrv : IUnknown
{
[helpstring("method StartCalc")] HRESULT StartCalc([in] VARIANT vrData);
[helpstring("method IsWorking")] HRESULT IsWorking([out] LONG* lWorking);
[helpstring("method GetResult")] HRESULT GetResult([out] FLOAT*
fResult);
[helpstring("method GetClientCnt")] HRESULT GetClientCnt([out] LONG* lClntCnt);
};
[
coclass,
threading("free"),
vi_progid("vect_len_p.CtrlSrv"),
progid("vect_len_p.CtrlSrv.1"),
version(1.0),
uuid("0AC0CB69-25D6-4d18-AF85-FB0FEB1501C7"),
helpstring("CtrlSrv Class")
]
class ATL_NO_VTABLE CCtrlSrv : public ICtrlSrv
{
public:
CCtrlSrv()
{
}
DECLARE_PROTECT_FINAL_CONSTRUCT()
HRESULT FinalConstruct(){return S_OK;}
void FinalRelease() {}
STDMETHOD(StartCalc)(VARIANT vrData);
STDMETHOD(IsWorking)(LONG* lWorking);
STDMETHOD(GetResult)(FLOAT* fResult);
STDMETHOD(GetClientCnt)(LONG* lClntCnt);
};
CtrlSrv.cpp
#include "stdafx.h"
#include "CtrlSrv.h"
//Объявляем внешние переменные:
extern CRITICAL_SECTION g_csData;
extern long g_lClnCnt;
extern long g_lGDClnCnt;
extern long g_lSDClnCnt;
extern int g_iElemCnt;
extern float g_flSum;
extern bool bStarted;
extern VARIANT g_vtData;
extern int g_iCurSlice;
extern HANDLE g_stEvent;
STDMETHODIMP CCtrlSrv::StartCalc(VARIANT vrData)
{
//Начало вычислений:
EnterCriticalSection(&g_csData);
//Сначала проверяем, не стартовали ли уже вычисления или достаточно ли //количество клиентов:
if(bStarted||g_lClnCnt<=0)
{
LeaveCriticalSection(&g_csData);
return E_FAIL;
}
//Начальное значение счетчика не получивших данные клиентов:
g_lGDClnCnt=g_lClnCnt-1;
//Начальное значение счетчика вернувших данные клиентов:
g_lSDClnCnt=g_lClnCnt;
g_flSum=0;//Начальное значение суммы
if(V_VT(&vrData)!=(VT_ARRAY|VT_R4)) return E_FAIL;//Неверный тип входных данных
SAFEARRAY *pSa;
pSa=V_ARRAY(&vrData);
long ub;
HRESULT hr=SafeArrayGetUBound(pSa,1,&ub);
if(FAILED(hr))
{
MessageBox(NULL,"Cannot get array bounds","Error",0);
return hr;
}
//Полученная верхняя граница на 1 меньше размера в элементах:
g_iElemCnt=ub+1;
VariantCopy(&g_vtData,&vrData);//Копирование одного варианта в другой
//Подсчитываем размер получаемых клиентами частей массива:
g_iCurSlice=g_iElemCnt/g_lClnCnt+1;
PulseEvent(g_stEvent);//Отпускаем ожидающие данные потоки
bStarted=true;//Вычисления только что начались
LeaveCriticalSection(&g_csData);
return S_OK;
}
STDMETHODIMP CCtrlSrv::IsWorking(LONG *lWorking)
{
/Возвращаем состояние флага работы:
EnterCriticalSection(&g_csData);
*lWorking=LONG(bStarted);
LeaveCriticalSection(&g_csData);
return S_OK;
}
STDMETHODIMP CCtrlSrv::GetResult(FLOAT* fResult)
{
//Получаем результат работы от сервера:
*fResult=0.0f;
if(bStarted) return E_FAIL;
EnterCriticalSection(&g_csData);
*fResult=g_flSum;
LeaveCriticalSection(&g_csData);
return S_OK;
}
STDMETHODIMP CCtrlSrv::GetClientCnt(LONG* lClntCnt)
{
//Вывод информации о текущем количестве клиентских машин:
EnterCriticalSection(&g_csData);
*lClntCnt=g_lClnCnt;
LeaveCriticalSection(&g_csData);
return S_OK;
}
3.7.3. Инициализация COM-сервера
Начальная инициализация COM-сервера выполняется в основном файле его проекта.
Vect_len_p.cpp
#include "stdafx.h"
#include "resource.h"
extern CRITICAL_SECTION g_csData;
extern HANDLE g_stEvent;
[ module(EXE, uuid = "{1ADC1F2E-BBFC-416D-8AE9-BAE7E0C5A351}", name = "vect_len_p", helpstring = "vect_len_p 1.0 Type Library",
resource_name = "IDR_VECT_LEN_P") ]
class Cvect_len_pModule
{
public:
Cvect_len_pModule()
{
InitializeCriticalSection(&g_csData);
g_stEvent=CreateEvent(NULL,true,false,NULL);
}
~Cvect_len_pModule()
{
DeleteCriticalSection(&g_csData);
CloseHandle(g_stEvent);
}
// Override CAtlExeModuleT members
};
3.7.4. Приложение-клиент вычислений
Схема функционирования клиента вычислений описывалась ранее. Он представляет собой обычное консольное приложение Windows. Листинг его основного модуля приведен ниже.
Vect_len_cln.cpp
#include "stdafx.h"
#define _WIN32_DCOM
#include "objbase.h"
//Импорт tlb-файла, содержащего описание интерфейсов COM-сервера
#import "..\vect_len_p\_vect_len_p.tlb" no_namespace named_guids
int _tmain(int argc, _TCHAR* argv[])
{
CoInitialize(NULL);//Инициализация подсистемы COM
COSERVERINFO sinfo;//Служебная структура
sinfo.pwszName=new WCHAR[128];//Место под имя машины
try
{
//Заполнение служебной структуры:
sinfo.dwReserved1=0;
sinfo.dwReserved2=0;
if(argc>1)
//Если есть аргументы командной строки, то первый из них - имя машины
mbstowcs(sinfo.pwszName,argv[1],128);
else
//Если аргументов нет, то предполагается соединение с локальной машиной
wcscpy(sinfo.pwszName,L"127.0.0.1");
sinfo.pAuthInfo=NULL;
IVectLenSrv *pObj;//Указатель на интерфейс
MULTI_QI qi={&IID_IVectLenSrv,NULL,0};
if(FAILED(CoCreateInstanceEx(CLSID_CVectLenSrv,NULL,
CLSCTX_REMOTE_SERVER,&sinfo,1,&qi)))
//Ошибка соединения:
::MessageBox(NULL,"Cannot connect to the server","Error",0);
else
{
//Соединение прошло успешно
pObj=(IVectLenSrv*)qi.pItf;
long rs,ub;
int iElemCnt=0;
VARIANT dt;
pObj->GetData(&dt,&rs);//Получение данных
if(!rs)//Только если нормальный код возврата
{
SAFEARRAY *pSa=V_ARRAY(&dt);
HRESULT hr=SafeArrayGetUBound(pSa,1,&ub);
iElemCnt=ub+1;
PVOID pvData;
hr=SafeArrayAccessData(pSa,&pvData);
float *pvFl,flSum=0.0f;
pvFl=(float *)pvData;
//Распечатка полученных элементов вектора и подсчет суммы:
for(int i=0;i<iElemCnt;i++)
{
printf("%.4f ",pvFl[i]);
flSum+=pvFl[i]*pvFl[i];
}
pObj->SetData(flSum);//Возвращаем результат серверу
}
pObj->Release();//Освобождаем объект
}
}
catch(_com_error&e)//Обработка ошибок COM
{
printf(e.ErrorMessage());
}
delete []sinfo.pwszName;
CoUninitialize();//Освобождаем COM-подсистему
return 0;
}
3.7.5. Приложение-клиент управления
Это приложение является диалоговым. Его внешний вид показан на рис. 9.
Рис. 9. Внешний вид управляющего клиента
Нажатие кнопки Generate приводит к созданию нового случайного вектора указанного размера. Кнопка Start отправляет текущий вектор серверу и инициирует процесс вычислений. При старте данной клиентской программы первым делом выводится окно, в котором можно выбрать машин сети, содержащую COM-сервер, нажатие Cancel приводит к подключению к локальному серверу.
Листинг основных модулей клиента управления приведен ниже.
Vect_len_ctrlDlg.h
#pragma once
#define _WIN32_DCOM
#include "objbase.h"
#import "..\vect_len_p\_vect_len_p.tlb" no_namespace named_guids
class Cvect_len_ctrlDlg : public CDialog
{
// Construction
public:
Cvect_len_ctrlDlg(CWnd* pParent = NULL);// standard constructor
enum { IDD = IDD_VECT_LEN_CTRL_DIALOG };
protected:
virtual void DoDataExchange(CDataExchange* pDX);// DDX/DDV support
protected:
HICON m_hIcon;
UINT_PTR m_iTimer;
int m_iVecCmpCnt;
float *m_pfVector;
ICtrlSrv *IObj;
// Generated message map functions
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
void GenerateData();
void UpdateVector();
void UpdateVectorCmpCnt();
void UpdateClientCnt(long lClntCnt);
void UpdateResult(float fResult);
public:
afx_msg void OnDestroy();
afx_msg void OnTimer(UINT nIDEvent);
afx_msg void OnBnClickedBnGener();
afx_msg void OnBnClickedStart();
};
Vect_len_ctrlDlg.cpp
#include "stdafx.h"
#include "vect_len_ctrl.h"
#include "vect_len_ctrlDlg.h"
#include ".\vect_len_ctrldlg.h"
#include "winuser.h"
Cvect_len_ctrlDlg::Cvect_len_ctrlDlg(CWnd* pParent /*=NULL*/)
: CDialog(Cvect_len_ctrlDlg::IDD, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void Cvect_len_ctrlDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(Cvect_len_ctrlDlg, CDialog)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
//}}AFX_MSG_MAP
ON_WM_DESTROY()
ON_WM_TIMER()
ON_BN_CLICKED(IDC_BN_GENER, OnBnClickedBnGener)
ON_BN_CLICKED(IDC_START, OnBnClickedStart)
END_MESSAGE_MAP()
BOOL Cvect_len_ctrlDlg::OnInitDialog()
{
...................................
//Инициализируем DCOM:
CoInitialize(NULL);
//Получаем адрес машины:
LPITEMIDLIST pIDL;
BROWSEINFOW pbi;
SHGetSpecialFolderLocation(this->GetSafeHwnd(), CSIDL_NETWORK, &pIDL);
pbi.hwndOwner=this->GetSafeHwnd();
pbi.ulFlags=BIF_BROWSEFORCOMPUTER;
pbi.pidlRoot=pIDL;
pbi.lpfn=NULL;
pbi.iImage=0;
pbi.lpszTitle=L"Choose server computer";
pbi.pszDisplayName=new WCHAR[MAX_PATH];
wcscpy(pbi.pszDisplayName,L"Roman");
COSERVERINFO sinfo;
sinfo.pwszName=new WCHAR[128];
//Открывает диалог с перечислением машин сети:
if(SHBrowseForFolderW(&pbi))
wcscpy(sinfo.pwszName,pbi.pszDisplayName);
else
//Это случае, если нажата кнопка Cancel:
wcscpy(sinfo.pwszName,L"127.0.0.1");
delete []pbi.pszDisplayName;
try
{
sinfo.dwReserved1=0;
sinfo.dwReserved2=0;
sinfo.pAuthInfo=NULL;
MULTI_QI qi={&IID_ICtrlSrv,NULL,0};
if(FAILED(CoCreateInstanceEx(CLSID_CCtrlSrv,NULL,
CLSCTX_REMOTE_SERVER,&sinfo,1,&qi)))
{
MessageBox("Cannot connect to the server","DCOM error",MB_OK);
SendMessage(WM_CLOSE);//Закрытие программы
}
else //Получение ссылки на класс управления COM-объекта:
IObj=(ICtrlSrv*)qi.pItf;
}
catch(_com_error&e)
{
MessageBox(e.ErrorMessage(),"DCOM error");
SendMessage(WM_CLOSE);//Закрытие программы
}
delete []sinfo.pwszName;
m_iVecCmpCnt=100;//Начальное значение количества компонент вектора
m_pfVector=NULL;
GenerateData();
UpdateVector();
UpdateVectorCmpCnt();
UpdateClientCnt(0);
UpdateResult(0.0f);
//Добавляем новый таймер, который будет отвечать за перерисовку //информации на окне:
m_iTimer=SetTimer(1,1000,0);
return TRUE; // return TRUE unless you set the focus to a control
}
void Cvect_len_ctrlDlg::UpdateClientCnt(long lClntCnt)
{
//Обновление информации о количестве подключенных клиентов:
CString str;
str.Format("%d",lClntCnt);
GetDlgItem(IDC_ED_CCNT)->SetWindowText(str);
}
void Cvect_len_ctrlDlg::UpdateResult(float fResult)
{
//Обновление информации о результате вычислений:
CString str;
str.Format("%.4f",fResult);
GetDlgItem(IDC_ED_VLEN)->SetWindowText(str);
}
void Cvect_len_ctrlDlg::UpdateVector()
{
//Обновление информации о векторе:
CListBox *lb=(CListBox*)GetDlgItem(IDC_LVECT);
lb->ResetContent();
CString str;
for(int i=0;i<m_iVecCmpCnt;i++)
{
str.Format("%.4f",m_pfVector[i]);
lb->AddString(str);
}
}
void Cvect_len_ctrlDlg::UpdateVectorCmpCnt()
{
//Обновление информации о количестве клиентов вычислений:
CString str;
str.Format("%d",m_iVecCmpCnt);
GetDlgItem(IDC_ED_VCCNT)->SetWindowText(str);
}
void Cvect_len_ctrlDlg::GenerateData()
{
//Создаем массив, содержащий компоненты вектора и заполняем его:
if(m_pfVector) delete []m_pfVector;
m_pfVector=new float[m_iVecCmpCnt];
for(int i=0;i<m_iVecCmpCnt;i++)
m_pfVector[i]=float(rand())/999.0f;
}
void Cvect_len_ctrlDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
....................................
}
void Cvect_len_ctrlDlg::OnPaint() {
....................................
}
HCURSOR Cvect_len_ctrlDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
void Cvect_len_ctrlDlg::OnDestroy()
{
CDialog::OnDestroy();
KillTimer(m_iTimer);//Уничтожаем созданный ранее таймер перерисовки
if(m_pfVector) delete []m_pfVector;
if(IObj) IObj->Release();//Освобождаем COM-объект
CoUninitialize();
}
void Cvect_len_ctrlDlg::OnTimer(UINT nIDEvent)
{
//Производим обновление данных по таймеру:
LONG tmp,itmp;
float ftmp;
IObj->IsWorking(&tmp);
if(!tmp)//Значит уже отработала или еще не приступала
{
WINDOWINFO wi;
GetDlgItem(IDC_START)-> GetWindowInfo(&wi);
if(wi.dwStyle&WS_DISABLED)
//Снова делаем кнопку Start доступной:
GetDlgItem(IDC_START)->EnableWindow(true);
IObj->GetResult(&ftmp);
UpdateResult(ftmp);
IObj->GetClientCnt(&itmp);
UpdateClientCnt(itmp);
}
CDialog::OnTimer(nIDEvent);
}
void Cvect_len_ctrlDlg::OnBnClickedBnGener()
{
//Перегенерация вектора:
CString str;
GetDlgItem(IDC_ED_VCCNT)->GetWindowText(str);
int iVecCmpCnt=atoi(str.GetBuffer());
if(iVecCmpCnt<3)
{
MessageBox("Invalid component count value. Must be numeric and more than 2","Error");
UpdateVectorCmpCnt();
}
else
{
m_iVecCmpCnt=iVecCmpCnt;
GenerateData();
UpdateVector();
UpdateVectorCmpCnt();
}
}
void Cvect_len_ctrlDlg::OnBnClickedStart()
{
//Начинаем вычисления:
VARIANT dt;
SAFEARRAYBOUND sab;
sab.cElements = m_iVecCmpCnt;sab.lLbound = 0;
HRESULT hr;
SAFEARRAY * pSa;
pSa = SafeArrayCreateEx(VT_R4,1,&sab,NULL);
if (pSa==NULL) {MessageBox("Cannot create array","Error");return;}
PVOID pvData;
hr=SafeArrayAccessData(pSa,&pvData);
if (FAILED(hr)) {SafeArrayDestroy(pSa);
MessageBox("Cannot access array data","Error");return;}
float *pvFl;
pvFl=(float *)pvData;
CopyMemory(pvFl,m_pfVector,sizeof(float)*m_iVecCmpCnt);
hr = SafeArrayUnaccessData(pSa);
if (FAILED(hr)) {SafeArrayDestroy(pSa);
MessageBox("Cannot unaccess array data","Error");return;}
VariantInit(&dt);
//Variant является массивом, причем массивом типа float:
V_VT(&dt)=VT_ARRAY|VT_R4;
V_ARRAY(&dt)=pSa;//Теперь добавляем данные
if(FAILED(IObj->StartCalc(dt)))
MessageBox("Cannot start calculation process. Possibly it is already run","Com error");
Else
//Временно делаем кнопку Start недоступной:
GetDlgItem(IDC_START)->EnableWindow(false);
}
4. ТРЕБОВАНИЯ К ОТЧЕТУ О ЛАБОРАТОРНОЙ РАБОТЕ
При выполнении работы по одному из выбранных заданий, варианты которых даны в следующем разделе, необходимо разработать параллельную программу, провести сравнение времени вычислений при разном количестве процессов и машин. Результаты работы процессов протоколировать в файл (*.log), листинг протокола поместить в отчет о работе, который должен содержать:
* постановку задачи;
* описание параллельного алгоритма;
* листинг программы;
* результаты работы, сравнительные характеристики работы программы для нескольких клиентов и машин (в т.ч. графики зависимости времени вычисления для нескольких процессов и машин);
* выводы по работе
5. ВАРИАНТЫ ЗАДАНИЙ
5.1. Поиск в файле
Реализовать параллельный поиск в файле, в том числе и по маске, например: "s??fgt" или "s*fgt". Поиск распараллеливается путём передачи разным рабочим станциям в сети (клиентам) разных фрагментов файлов.
5.2. Сортировка транспозициями
Рис. 10. Пример сортировки транспозициями 16-элементного массива за 6 итераций
При сортировке N-элементного массива M клиентами i-му из них на четных итерациях передается отрезок массива из N/M элементов с номерами (N/M)(i-1)+1,..., (N/M)i, i=1,M, на нечетных - с номерами (N/M)(i-1)+1+N/(2M),..., (N/M)i+ N/(2M), i=1,M-1. После сортировки каждый клиент возвращает обратно свою часть. При сортировке следует учитывать, что на всех итерациях, кроме 0-й (первой хронологически) получаемая каждым клиентом часть состоит из двух равных частей - старшей и младшей - уже отсортированных. Описание этого алгоритма применительно к многопроцессорным SIMD-системам приведено в [6]. На рис.10 приведен пример сортировки.
5.3. Сортировка Шелла
Необходимо реализовать параллельную сортировку Шелла. Идея алгоритма состоит в обмене элементов, расположенных не только рядом, но и далеко друг от друга, что значительно сокращает общее число операций перемещения элементов. Как пример рассматривается файл из 2n элементов. На j-м шаге файл делится на 2j групп по 2n-j элементов в каждой, при этом i-я группа содержит элементы (i, i+1*2n-j , i+2*2n-j , .., i+(2j -1)*2n-j ), i=1,.., 2j , j=n-1,..,1 (номер шага убывает от n-1 до 1). На каждом шаге выполняется сортировка в каждой группе. При сортировке в каждой группе следует иметь ввиду, что элементы с четными (нечетными) номерами образуют уже отсортированную последовательность, то есть для сортировки группы надо слить эти две отсортированные подпоследовательности [7].
5.4. Сортировка слиянием
Алгоритмы слияния основываются на процедуре слияния двух уже отсортированных отрезков массива в один. При параллельной сортировке весь процесс разбивается на итерации. На первой итерации массив разбивается на фрагменты, общее количество которых превышает количество клиентов в два раза. Затем каждая пара фрагментов сливается одним из процессов, после чего фрагмент записывается в сортируемый массив. Все следующие итерации идентичны первой за исключением уменьшения работающих процессов вдвое на каждой из итераций. Последняя пара фрагментов может быть слита на сервере.
5.5. Шифрование методом замены (моноалфавитная подстановка)
В этом методе символы шифруемого текста заменяются символами, взятыми из одного (одноалфавитная или моноалфавитная подстановка) алфавита. Самой простой разновидностью является прямая замена, когда буквы шифруемого сообщения заменяются другими буквами того же самого или некоторого другого алфавита. Таблица замены может иметь следующий вид:
Символы шифруемого текстаA B C D E F G H I J K L M N O P Q R S T U V W X Y ZЗаменяющие символыS P X L R Z I M A Y E D W T B G V N J O C F H Q U K5.6. Шифрование методом замены (полиалфавитная подстановка)
При полиалфавитной подстановке для замены символов исходного текста используются несколько алфавитов, заданных данным ключом, причем смена алфавитов осуществляется последовательно и циклически, т.е. первый символ заменяется соответствующим символом первого алфавита, второй - символом второго алфавита и т.д. до тех пор, пока не будут использованы все выбранные алфавиты. После этого использование алфавитов повторяется.
5.7. Шифрование методом гаммирования
Суть этого метода состоит в том, что символы шифруемого текста последовательно складываются с символами некоторой специальной последовательности, называемой гаммой. Иногда такой метод представляют как наложение гаммы на исходный текст, поэтому он получил название "гаммирование".
Процедуру наложения гаммы на исходный текст можно осуществить двумя способами. При первом способе символы исходного текста и гаммы заменяются цифровыми эквивалентами, которые затем складываются по модулю k, где k - число символов в алфавите, т.е.
tш =(tо + tг)mod k,
гдеtш- символы зашифрованного текста;
tо- символы исходного текста;
tг- символы гаммы.
При втором методе символы исходного текста и гаммы представляются в виде двоичного кода, затем соответствующие разряды складываются по модулю два.
5.8. Произведение матриц
Произведением AB матрицы A(mxn)=(aij) на матрицу B(nxk)=(bij) является матрица С(mxk)=(сij), где
cij = aiv bj , гдеi=1,2,...,m, j=1,2,...,k.
Для распараллеливания вычислений между L клиентами за каждым из них закрепляются m*k/L элементов результирующей матрицы. Например, при L=m за i-м клиентом закрепляется i-я строка матрицы С, i=1..m. 6. КОНТРОЛЬНЫЕ ВОПРОСЫ
* Что такое интерфейс, сокласс?
* Как клиент вызывает метод сервера?
* Что такое proxy, stub?
* Какие варианты COM-серверов бывают?
* Какие програмные средства нужны для использования DCOM в Win 95/98?
* Как производится настройка DCOM на стороне клиента?
* Как производится настройка DCOM на стороне сервера?
* Как создать сервер в Visual C++?
* Как создать клиента в Visual C++?
* Как клиент создает proxy?
БИБЛИОГРАФИЧЕСКИЙ СПИСОК
1. Арчер Т., Уайтчепел Э. Visual C++.NET. Библия пользователя.: Пер. с англ. - М.: Издательский дом "Вильямс", 2003. - 1216 с.
2. Оберг Р.Дж. Технология COM+. Основы и программирование.: Пер. с англ.: Уч. пос. - М.: Издательский дом "Вильямс", 2000. - 480 с.
3. http://www.cppclub.newmail.ru
4. Рули Д. и др. Сети Windows NT 4.0. - K.: BHV, Век, 1997.
5. http://mirror.urbannet.ru/
6. Чефранов А.Г. Параллельное программирование. Таганрог: Изд-во ТРТУ, 2000. 113 с.
7. Кнут Д. Искусство программирования. Том 3. Сортировка и поиск. - Изд-во: Вильямс, 2000 г., 500 с.
СОДЕРЖАНИЕ
ВВЕДЕНИЕ3
1. ЦЕЛЬ РАБОТЫ3
2. ОСНОВНЫЕ ТЕОРЕТИЧЕСКИЕ СВЕДЕНИЯ3
2.1. ТЕХНОЛОГИЯ COM3
2.2. ОСОБЕННОСТИ ТЕХНОЛОГИИ DCOM5
2.3. ОСНОВНЫЕ ПРИНЦИПЫ ПОСТРОЕНИЯ РАСПРЕДЕЛЕННЫХ ПРИЛОЖЕНИЙ7
3. ПРИМЕР ВЫПОЛНЕНИЯ РАБОТЫ В СРЕДЕ VISUAL C++.NET7
3.1. НАЧАЛЬНЫЕ СВЕДЕНИЯ7
3.2. РАЗРАБОТКА СТРУКТУРЫ ПРИЛОЖЕНИЯ7
3.3. ПРЕДВАРИТЕЛЬНЫЕ ДЕЙСТВИЯ8
3.4. СОЗДАНИЕ СЕРВЕРНОЙ ЧАСТИ9
3.5. СОЗДАНИЕ КЛИЕНТСКОГО ПРИЛОЖЕНИЯ13
3.6. РЕКОМЕНДАЦИИ ПО НАСТРОЙКЕ КЛИЕНТА И СЕРВЕРА DCOM14
3.7. ПРОГРАММНАЯ РЕАЛИЗАЦИЯ17
3.7.1 Программная реализация COM-объекта вычислений17
3.7.2 Программная реализация COM-объекта контроля20
3.7.3. Инициализация COM-сервера23
3.7.4. Приложение-клиент вычислений23
3.7.5. Приложение-клиент управления25
4. ТРЕБОВАНИЯ К ОТЧЕТУ О ЛАБОРАТОРНОЙ РАБОТЕ30
5. ВАРИАНТЫ ЗАДАНИЙ31
5.1. ПОИСК В ФАЙЛЕ31
5.2. СОРТИРОВКА ТРАНСПОЗИЦИЯМИ31
5.3. СОРТИРОВКА ШЕЛЛА32
5.4. СОРТИРОВКА СЛИЯНИЕМ32
5.5. ШИФРОВАНИЕ МЕТОДОМ ЗАМЕНЫ (МОНОАЛФАВИТНАЯ ПОДСТАНОВКА)32
5.6. ШИФРОВАНИЕ МЕТОДОМ ЗАМЕНЫ (ПОЛИАЛФАВИТНАЯ ПОДСТАНОВКА)33
5.7. ШИФРОВАНИЕ МЕТОДОМ ГАММИРОВАНИЯ33
5.8. ПРОИЗВЕДЕНИЕ МАТРИЦ33
6. КОНТРОЛЬНЫЕ ВОПРОСЫ33
БИБЛИОГРАФИЧЕСКИЙ СПИСОК35
Троценко Роман Владимирович
Чефранов Александр Георгиевич
Беспалов Павел Александрович
Руководство к лабораторной работе
Параллельные вычисления на сетевых кластерах с помощью технологии DCOM и VISUAL C++.NET
Ответственный за выпуск Троценко Р.В.
Редактор Васютина О.К.
Корректор Проценко И.А., Селезнева Н.И.
ЛР № 020565 от 23 июня 1997 г. Подписано к печати Формат 60x84 1/16.Бумага офсетная
Офсетная печать
Усл. п.л. - 2,3.Уч.-изд. л. - 2,2.
Заказ №Тираж 150 экз.
Издательство Таганрогского государственного радиотехнического университета
ГСП 17А, Таганрог, 28, Некрасовский, 44
Типография Таганрогского государственного радиотехнического университета
ГСП 17А, Таганрог, 28, Энгельса, 1
Документ
Категория
Рефераты
Просмотров
921
Размер файла
604 Кб
Теги
dcom
1/--страниц
Пожаловаться на содержимое документа