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


Проблемы с потоковой обработкой сервера

Сервер в процессе не вызывает CoInitialize, CoInitializeEx или OleInitialize, чтобы пометить модель потоков. Для объектов DLL на основе потоков или внутрипроцессных объектов необходимо задать модель потоков в реестре. Модель по умолчанию, если не указать модель потоковой обработки, является однопотоковой для каждого процесса. Чтобы указать модель, добавьте значение ThreadingModel в раздел InprocServer32 в реестре.

Библиотеки DLL, поддерживающие создание экземпляра объекта класса, должны реализовывать и экспортировать функции DllGetClassObject и DllCanUnloadNow. Если клиент хочет, чтобы экземпляр класса, поддерживаемый библиотекой DLL, вызов CoGetClassObject (напрямую или через вызов CoCreateInstance) вызывает DllGetClassObject, чтобы получить указатель на его объект класса при реализации объекта в библиотеке DLL. Таким образом, DllGetClassObject должен иметь возможность выдавать несколько объектов класса или один потокобезопасный объект (по сути, с помощью InterlockedIncrement Intercrement InterlockedDecrement/ в их внутренних счетчиках ссылок).

Как подразумевает его имя, вызывается dllCanUnloadNow, чтобы определить, используется ли библиотека DLL, которая реализует ее, что позволяет вызывающему объекту безопасно выгрузить его, если он не является. Вызовы CoFreeUnusedLibraries из любого потока всегда направляются через поток основной квартиры для вызова DllCanUnloadNow.

Как и другие серверы, внутрипроцессные серверы могут быть однопоточными, многопоточными или свободными. Эти серверы могут использоваться любым клиентом OLE независимо от модели потоков, используемой этим клиентом.

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

Если объект внутри процесса, поддерживающий однопоточную модель, вызывается одновременно несколькими потоками клиента, COM не может разрешить клиентским потокам напрямую обращаться к интерфейсу объекта", объект не был разработан для такого доступа. Вместо этого COM должен убедиться, что вызовы синхронизированы и выполняются только клиентским потоком, создающим объект. Таким образом, COM создает объект в главной квартире клиента и требует, чтобы все остальные клиентские квартиры были доступны для доступа к объекту с помощью прокси-серверов.

Когда в клиенте создается бесплатный поток квартиры (многопоточная модель квартиры) создается сервер внутрипроцессного процесса, COM запускает поток однопоточной модели квартиры "host" в клиенте. Этот поток узла создаст объект, а указатель интерфейса будет маршалирован обратно в бесплатную потоковую квартиру клиента. Аналогичным образом, когда однопоточная квартира в клиенте модели квартиры создает свободный поток внутрипроцессного сервера, COM создает поток узла с бесплатным потоком (многопоточная квартира, на которой будет создан объект, а затем маршалирован обратно в клиент однопотоковую квартиру).

Примечание.

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

 

COM помогает защитить доступ к объектам, предоставляемым однопоточной библиотекой DLL, требуя доступа из той же клиентской квартиры, в которой они были созданы. Кроме того, все точки входа DLL (например, DllGetClassObject и DllCanUnloadNow) и глобальные данные всегда должны быть доступны одной квартире. COM создает такие объекты в главной квартире клиента, предоставляя главной квартире прямой доступ к указателям объекта. Звонки из других квартир используют межпоточное маршалинг, чтобы перейти от прокси-сервера к заглушку в главной квартире, а затем к объекту. Это позволяет COM синхронизировать вызовы объекта. Межпоточные вызовы медленны, поэтому рекомендуется переписать эти серверы для поддержки нескольких квартир.

Как и однопоточный сервер процесса, объект, предоставляемый библиотекой DLL модели квартиры, должен получить доступ к той же клиентской квартире, из которой она была создана. Однако объекты, предоставляемые этим сервером, можно создавать в нескольких квартирах клиента, поэтому сервер должен реализовать точки входа (например, DllGetClassObject и DllCanUnloadNow) для многопоточного использования. Например, если две квартиры клиента пытаются создать два экземпляра объекта в процессе одновременно, dllGetClassObject может вызываться одновременно обеими квартирами. Библиотека DLLCanUnloadNow должна быть написана таким образом, чтобы библиотека DLL не выгрузилась, пока код по-прежнему выполняется в библиотеке DLL.

Если библиотека DLL предоставляет только один экземпляр фабрики классов для создания всех объектов, реализация фабрики классов также должна быть разработана для многопоточного использования, так как к нему будет обращаться несколько клиентских квартир. Если библиотека DLL создает новый экземпляр фабрики классов при каждом вызове DllGetClassObject , фабрика классов не должна быть потокобезопасной.

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

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

Чтобы ускорить производительность для свободного доступа к объектам DLL в процессе, COM предоставляет функцию CoCreateFreeThreadedMarshaler. Эта функция создает объект маршалинг с бесплатным потоком, который можно агрегировать с помощью объекта сервера в процессе. Если клиентская квартира в том же процессе нуждается в доступе к объекту в другой квартире, агрегирование свободного маршалера предоставляет клиенту прямой указатель на объект сервера, а не прокси- сервер, когда клиент маршалирует интерфейс объекта в другую квартиру. Клиенту не нужно выполнять синхронизацию. Это работает только в рамках одного процесса; Стандартное маршалинг используется для ссылки на объект, который отправляется в другой процесс.

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

Доступ к интерфейсам между квартирами

Выбор модели потоков

Многопоточные квартиры

Процессы, потоки и квартиры

Однопоточное и многопоточное взаимодействие

Квартиры с одним потоком