Страницы

4 июня 2012 г.

COM - объекты. Параметры фабрики классов.

Приветствую Вас в блоге "Будни программиста".

       Я заметил, что многие задают вопросы типа "А как сделать чтобы к одному Com-серверу можно было подключиться множеством клиентов?", "А как сделать чтоб для всех клиентов создавался один объект на сервере?" и т.д.
       Совсем недавно, немного познакомившись с технологией COM, я и сам искал ответы на эти вопросы. В этом посте я постараюсь подвести итог моих поисков.
Итак, имеется два параметра фабрики классов управляющие генерацией COM-объектов на сервере:
  • Instancing;
  • Threading Model;


       Параметр Instancing управляет тем как будет создаваться COM-объект. Имеется три варианта:
  1. Internal. Это внутренний объект, который используется внутри процесса, такой объект не регистрируется в системе и не может создаваться внешними клиентами. 
  2. Single Instance. Каждый клиент работает со своей копией сервера. При таком параметре не возможно подключение к одному COM-серверу нескольких клиентов. Другими словами, после того как клиент получает указатель на зарегистрированную таким о фабрику класса только этот клиент и будет ее видеть. ВАЖНО: Данная настройка означает, что каждого клиента будет запускаться отдельная копия внешнего сервера. Один клиент может создать у себя несколько COM-объектов, и все они будут разными. Это является отличием от синглтона, с которым часто путают Single Instance.
  3. Multiple Instance. Фабрика класса будет доступна ВСЕМ клиентам, независимо от того кто первый ее использовал. При подключении нового клиента сервер генерирует новый экземпляр COM-объекта, ссылка на который достается клиенту. Таким образом мы получаем один сервер с возможностью подключения множества клиентов. (Лично не проверял, но предполагаю, что при подключении большого количества клиентов работа сервера будет изрядно затруднена).
       Второй параметр: Threading Model (нитевая модель).

       Threading Model - это своего рода контракт, заключаемый между COM-объектом и операционной системой по синхронизации в случае распараллеливания работы на несколько нитей. Этот контракт определяет разграничение ответственности — в каких случаях сервер самостоятельно реализует синхронизацию доступа к данным из разных нитей, в каких это за него делает система.
       Чтобы понять архитектуру потоков COM, можно себе представить, что все объекты COM в процессе поделены на группы, называемые апартаментами. Поскольку COM объект живет в точности в одном апартаменте, его методы могут быть непосредственно вызваны только из потока, который принадлежит этому апартаменту. Любой другой поток, который хочет вызвать объект, должен это делать через заместителя (proxy).
       Апартаменты бывают двух типов: однопоточные (STA – Single-threaded Apartments) и многопоточные (MTA – Multi-threaded Apartments).


STA – Single-threaded Apartments

       В STA каждый поток, который использует OLE, находится в отдельном апартаменте и COM синхронизирует все входящие вызовы с помощью очереди оконных сообщений. Для этого COM неявно создает окно и при вызове любого метода объекта посылает этому окну сообщение с помощью функции PostMessage. (Функция PostMessage создает MSG структуру для сообщения и копирует ее в очередь сообщений окна.) Процесс с единственным потоком выполнения может служить иллюстрацией этой модели.
       STA апартаменты имеют в точности один поток, так что все объекты, которые «живут» в однопоточном апартаменте, могут получать вызовы методов только от одного потока, который принадлежит этому апартаменту.
       Главным достоинством апартамента STA является то, что разработка объекта COM и клиентской части проста в том смысле, что нет нужды заботиться о синхронизации вызовов методов и их выполнения: следующий метод начнет выполняться только после того, как закончится выполнение предыдущего. Аналогично не нужно заботиться о синхронизации доступа к данным объекта.
       Главным недостатком апартамента STA является его неэффективность. Даже если синхронизация вызовов методов и не нужна, она все равно выполняется.
       Несмотря на это, предпочтительнее всегда использовать апартамент STA за исключением тех случаев, когда реализация конкретного сервера в рамках модели STA попросту невозможна.


MTA – Multi-threaded Apartments

       В MTA несколько потоков в одном апартаменте и обращения потоков объект должен синхронизировать самостоятельно.
MTA апартаменты имеют произвольное число потоков, так что все объекты, которые «живут» в таком апартаменте, могут принимать вызовы их методов от любого из потоков, который принадлежит этому апартаменту. Потоки в MTA использует модель, называемую свободной потоковой (free-threading). Для MTA COM автоматически поддерживает пул потоков и при поступлении очередного вызова метода отыскивает любой свободный поток и передает обработку ему. Таким образом, в любой момент времени клиент может вызывать разные методы из разных потоков или один и тот же метод. Если какой-либо метод объекта выполняется длительное время, это не означает, что другой клиент или поток будет ожидать завершения этого метода.
       Основным достоинством MTA апартамента является потенциально высокая производительность сервера, вследствие чего он более доступен для клиентов. Вместе с тем разработка объектов такого сервера намного сложнее, так как требуется синхронизировать не только вызовы методов, но и обращение к локальным данным объектов.
       Любой процесс может иметь произвольное число STA и MTA апартаментов, в том числе нулевое.

Параметр может принимать следующие значения:
  1. Single. Клиентские запросы сериализуются стандартным механизмом вызова. С этой потоковой моделью клиенты обрабатываются по одному (если их несколько - по очереди), следовательно, никакая дополнительная поддержка или обработка потоков не требуется. Если процесс имеет только один STA апартамент, то эта модель называется моделью одного потока (single-threaded model). Эта модель используется обычно для внутрипроцессных серверов (DLL библиотека) и при их регистрации в реестре не создается ключ Threadingmodel (Single в Delphi). Нет поддержки потоков – запросы клиентов выполняются последовательно.
  2. Apartment. Процесс, имеющий несколько STA апартаментов и ни одного апартамента MTA, использует модель разделенных потоков (apartment-threaded model). Для DLL-сервера в реестре будет записан ключ Threadingmodel=”Apartment”, а для EXE-сервера будет создан апартамент STA. Клиенты могут вызывать методы объекта только из потока, в котором объект был создан. Различные объекты одного и того же сервера могут быть вызваны из разных потоков, однако каждый объект может вызываться только из одного потока. Локальные данные каждого экземпляра объекта в безопасности, а глобальные данные должны быть защищены с использованием критических секций или каким-либо иным способом. Имеет некоторые преимущества. Объекты легки в разработке, однако клиентам придется решать более сложные задачи.
  3. Free. Процесс имеет один или несколько MTA апартаментов и ни одного STA. Эта модель называется моделью свободных потоков (free-threaded model). Для DLL-сервера в реестре будет записан ключ Threadingmodel=”Free”, а для EXE-сервера будет создан апартамент MTA. Клиенты могут вызывать любые методы объекта из любого потока в любое время. Объекты могут обрабатывать любое число потоков в любое время. Они должны защищать глобальные данные и данные экземпляров с помощью критических секций или каким-либо другим методом, защищающим некоторую последовательность кода. Клиенты программируются легко, однако объекты более сложны в разработке. Используется в первую очередь в распределенных средах DCOM.
  4. Both. Модель смешанных потоков (both-threded model): имеются MTA и STA апартаменты. Для DLL-сервера в реестре будет записан ключ Threadingmodel=”Both”, а для EXE-сервера будет создан апартамент MTA. Объекты могут поддерживать клиентов, которые используют модели apartment или free. Максимум производительности и гибкости. Клиенты могут использовать одно-поточную или многопоточную модель для повышения производительности.
  5. Neutral. Модель нейтральных потоков (neutral-threaded model), близкая к модели Both. Для DLL-сервера в реестре будет записан ключ Threadingmodel=”Neutral”, а для EXE-сервера будет создан апартамент MTA Модель нейтральных потоков отличается от модели смешанных потоков тем, что, во-первых, для ее поддержки нужна COM+, и, во-вторых, она несколько упрощает синхронизацию потоков. Суть синхронизации заключается в том, что если какой-либо клиент вызвал метод объекта, то другой клиент не сможет вызвать этот же метод до тех пор, пока метод не завершится. Если все методы работают только со «своими» данными, то в этом случае отпадает необходимость и в синхронизации доступа к полям объекта.

       Обе стороны приложения – клиентская и серверная – указывают COM, каким она должна следовать правилам в использовании потоков при инициализации COM объекта. Если обе стороны поддерживают одну и ту же модель, COM устанавливает между ними прямую связь и считает, что обе стороны соблюдают правила взаимодействия. Если стороны придерживаются разных правил, COM включает механизм маршалинга так, что каждая из сторон видит только те правила, которые она знает. Конечно, это снижает производительность, однако обеспечивает корректное взаимодействие клиента и сервера.
       Необходимо отметить, что выбранная в мастере потоковая модель только то, как объект заявляет себя в реестре. Разработчик должен сам обеспечить соответствующую выбранной модели реализацию объекта.
Потоковая модель подлинна только для внутрипроцессных серверов. Установка потоковой модели в мастере обеспечивает только установку соответствующей модели в системном реестре для внутрипроцессного сервера. Внепроцессные (локальные и удаленные) серверы регистрируются как исполняемые файлы (exe) и разработчик сам должен побеспокоиться о соответствующей реализации модели.
Замечание. Локальные переменные всегда в безопасности независимо от потоковой модели, так как они размещаются в стеке, а каждый поток имеет свой собственный стек.


Основа для написания статьи была взята тут

1 комментарий: