Поделиться через


Вспомогательные средства реализации внепроцессного сервера

Для упрощения задания написания кода сервера доступны четыре вспомогательные функции, которые могут вызываться внепроцессными серверами. Клиенты COM и серверы обработки COM обычно не вызывают их. Эти функции предназначены для предотвращения условий гонки в активации сервера, когда серверы имеют несколько квартир или несколько объектов класса. Однако они также могут использоваться для серверов объектов одного потока и объектов одного класса. Функции приведены следующим образом:

Чтобы завершить работу правильно, com-сервер должен отслеживать количество экземпляров объектов, которые он создал, и сколько раз вызывается метод IClassFactory::LockServer . Только если оба из этих счетчиков достигают нуля, сервер может завершить работу. На однопоточных COM-серверах решение о завершении работы было согласовано с входящими запросами активации, которые были сериализованы очередью сообщений. Сервер после получения выпуска в окончательном экземпляре объекта и принятия решения о завершении работы отменит его объекты класса до отправки дополнительных запросов на активацию. Если запрос на активацию поступил после этого момента, COM распознает, что объекты класса были отозваны и возвратят ошибку диспетчеру управления службами (SCM), что приведет к запуску нового экземпляра локального сервера.

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

Чтобы упростить обработку этих типов состояний гонки для записи серверов, COM предоставляет две функции подсчета ссылок:

  • CoAddRefServerProcess увеличивает глобальный счетчик ссылок на процесс.
  • CoReleaseServerProcess уменьшает глобальное число ссылок на процесс.

Когда глобальное число ссылок на процесс достигает нуля, COM автоматически вызывает CoSuspendClassObjects, что предотвращает появление новых запросов активации. Затем сервер может отменить регистрацию различных объектов класса из различных потоков на досуге, не беспокоясь о том, что другой запрос активации может прийти в систему. Все новые запросы активации отсюда обрабатываются SCM, запуская новый экземпляр локального процесса сервера.

Самый простой способ использования этих функций для локального серверного приложения заключается в вызове CoAddRefServerProcess в конструкторе для каждого объекта экземпляра и в каждом из методов IClassFactory::LockServer, когда параметр fLock имеет значение TRUE. Серверное приложение также должно вызывать CoReleaseServerProcess в деструкторе каждого объекта экземпляра и в каждом из методов IClassFactory::LockServer , если параметр fLock имеет значение FALSE.

Наконец, серверное приложение должно обратить внимание на код возврата из CoReleaseServerProcess, и если он возвращает значение 0, серверное приложение должно инициировать очистку, которая, как правило, для сервера с несколькими потоками означает, что он должен сигнализировать о различных потоках, чтобы выйти из циклов сообщений и вызвать CoAddRefServerProcess и CoReleaseServerProcess. Если используются функции управления временем существования серверного процесса, они должны использоваться как в экземплярах объектов, так и в методе LockServer ; в противном случае серверное приложение может завершиться преждевременно.

Когда выполняется запрос CoGetClassObject, COM обращается к серверу, маршалирует интерфейс IClassFactory объекта класса, возвращается в клиентский процесс, отменяет обработку интерфейса IClassFactory и возвращает его клиенту. На этом этапе клиенты обычно вызывают LockServer с true , чтобы предотвратить завершение работы процесса сервера. Однако существует время между маршалированием объекта класса и при вызове LockServer , в котором другой клиент может подключиться к тому же серверу, получить экземпляр и освободить этот экземпляр, что привело к тому, что сервер завершает работу и оставляет первый клиент высоким и сухим с отключенным указателем IClassFactory . Чтобы предотвратить это состояние гонки, COM добавляет неявный вызов LockServer с true в объект класса при маршалинге интерфейса IClassFactory и неявном вызове LockServer с false, когда клиент освобождает интерфейс IClassFactory. Поэтому не требуется удаленный вызов LockServer на сервер, а прокси-сервер для LockServer просто возвращает S_OK без фактического удаленного взаимодействия с вызовом.

Во время инициализации процесса внепроцессного сервера существует другое условие гонки, связанное с активацией. COM-сервер, регистрирующий несколько классов, обычно вызывает CoRegisterClassObject с REGCLS_LOCAL_SERVER для каждого CLSID, который поддерживается. После этого для всех классов сервер вводит свой цикл сообщений. Для однопоточного COM-сервера все запросы активации блокируются до тех пор, пока сервер не войдет в цикл сообщений. Однако для сервера модели квартиры, который регистрирует различные объекты класса в разных квартирах и для всех серверов с бесплатным потоком, запросы активации могут поступать раньше, чем это. В случае серверов модели квартир запросы на активацию могут поступать сразу после ввода цикла сообщений в любой поток. В случае с серверами с бесплатным потоком запрос активации может поступать сразу после регистрации объекта первого класса. Так как активация может произойти раньше, можно также выполнить окончательный выпуск (и, следовательно, начать завершение работы сервера) до завершения инициализации остальной части сервера.

Чтобы устранить эти условия гонки и упростить задание записи сервера, любой сервер, который хочет зарегистрировать несколько объектов класса с помощью COM, должен вызвать CoRegisterClassObject с REGCLS_LOCAL_SERVER | REGCLS_SUSPENDED для каждого отдельного CLSID, который поддерживает сервер. После регистрации всех классов и готовности к принятию входящих запросов на активацию сервер должен выполнить один вызов CoResumeClassObjects. Эта функция сообщает COM сообщить SCM обо всех зарегистрированных классах, и начинает выполнять запросы активации в процессе сервера. Использование этих функций обеспечивает следующие преимущества:

  • В SCM выполняется только один вызов независимо от количества зарегистрированных clSID, что снижает общее время регистрации (и, следовательно, время запуска серверного приложения).
  • Если сервер имеет несколько квартир и разные CLSID регистрируются в разных квартирах, или если сервер является бесплатным потоком сервера, запросы на активацию не будут поступать, пока сервер не вызывает CoResumeClassObjects, предоставляя серверу возможность регистрировать все свои CLSID и правильно настраиваться, прежде чем иметь дело с запросами активации и возможными запросами на завершение работы.

Обязанности COM-сервера