апартаменты Single-Threaded
Использование однопоточных квартир (процесс модели квартир) предлагает парадигму на основе сообщений для работы с несколькими объектами, работающими одновременно. Он позволяет создавать более эффективный код, разрешая потоку, пока он ожидает завершения некоторой операции, которая занимает много времени, чтобы разрешить выполнение другого потока.
Каждый поток в процессе, который инициализирован как процесс модели квартиры, и который извлекает и отправляет сообщения окна, является потоком с одним потоком квартиры. Каждый поток живет в своей квартире. В квартире указатели интерфейса могут передаваться без маршалинга, поэтому все объекты в одном потоке квартиры напрямую взаимодействуют.
Логическое группирование связанных объектов, которые выполняются в одном потоке и поэтому должны иметь синхронное выполнение, может жить в одном потоке квартиры. Однако объект модели квартиры не может находиться в нескольких потоках. Вызовы объектов в других потоках должны выполняться в контексте собственного потока, поэтому распределенные com-коммутаторы автоматически передают потоки при вызове прокси-сервера.
Межпроцессные и межпоточные модели похожи. Если необходимо передать указатель интерфейса на объект в другой квартире (в другом потоке) в рамках одного процесса, используется та же модель маршалинга, которую объекты в разных процессах используют для передачи указателей через границы процесса. Получив указатель на стандартный объект маршалинга, вы можете маршалировать указатели интерфейса через границы потоков (между квартирами) так же, как и между процессами. (Указатели интерфейса должны маршалироваться при передаче между квартирами.)
Правила для однопоточных квартир просты, но важно тщательно следовать им:
- Каждый объект должен жить только на одном потоке (внутри однопоточной квартиры).
- Инициализация COM-библиотеки для каждого потока.
- Маршал всех указателей на объекты при передаче их между квартирами.
- Каждая однопоточная квартира должна иметь цикл сообщений для обработки вызовов из других процессов и квартир в рамках одного процесса. Однопоточные квартиры без объектов (только клиента) также требуют цикла сообщений для отправки широковещательных сообщений, используемых некоторыми приложениями.
- Объекты, основанные на библиотеке DLL или в процессе, не вызывают функции инициализации COM; Вместо этого они регистрируют свою модель потоков в ThreadingModel именованным значением в разделе InprocServer32 в реестре. Объекты с поддержкой квартир также должны тщательно записывать точки входа DLL. Существуют особые рекомендации, которые применяются к потокам внутрипроцессных серверов. Дополнительные сведения см. в разделе In-Process Проблемы с потоком сервера.
Хотя несколько объектов могут жить в одном потоке, объект модели квартиры не может жить в нескольких потоках.
Каждый поток клиентского процесса или внепроцессного сервера должен вызывать CoInitializeили вызывать CoInitializeEx и указывать COINIT_APARTMENTTHREADED для параметра dwCoInit. Основная квартира — это поток, который сначала вызывает CoInitializeEx. Сведения о внутрипроцессных серверах см. в разделе In-Process Проблемы потоков сервера.
Все вызовы объекта должны выполняться в потоке (в пределах своей квартиры). Запрещено вызывать объект непосредственно из другого потока; использование объектов в этом свободном потоке может вызвать проблемы для приложений. Это правило связано с тем, что все указатели на объекты должны маршалироваться при передаче между квартирами. COM предоставляет следующие две функции для этой цели:
- CoMarshalInterThreadInterfaceInStream маршалирует интерфейс в объект потока, возвращаемый вызывающей объекту.
- CoGetInterfaceAndReleaseStream отменяет указатель интерфейса из объекта потока и освобождает его.
Эти функции обтекают вызовы CoMarshalInterface и функции CoUnmarshalInterface, которые требуют использования флага MSHCTX_INPROC.
Как правило, маршалинг выполняется автоматически com. Например, при передаче указателя интерфейса в качестве параметра в вызове метода прокси-сервера объекту в другой квартире или при вызове CoCreateInstanceCOM выполняет маршалинг автоматически. Однако в некоторых особых случаях, когда модуль записи приложений передает указатели интерфейса между квартирами без использования обычных механизмов COM, модуль записи должен обрабатывать маршалинг вручную.
Если одна квартира (квартира 1) в процессе имеет указатель интерфейса, а другая квартира (квартира 2) требует его использования, квартира 1 должна вызывать CoMarshalInterThreadInterfaceInStream для маршалирования интерфейса. Поток, созданный этой функцией, является потокобезопасным и должен храниться в переменной, доступной в квартире 2. Квартира 2 должна передать этот поток в CoGetInterfaceAndReleaseStream, чтобы отменить удаление интерфейса и вернуть указатель на прокси-сервер, через который он может получить доступ к интерфейсу. Основная квартира должна оставаться в живых, пока клиент не завершит всю работу COM (поскольку некоторые внутрипроцессные объекты загружаются в главной квартире, как описано в разделе In-Process Проблемы потоков сервера). После передачи одного объекта между потоками таким образом очень легко передавать указатели интерфейса в качестве параметров. Таким образом распределенный COM выполняет маршалинг и переключение потоков для приложения.
Для обработки вызовов из других процессов и квартир в рамках одного процесса каждая однопоточная квартира должна иметь цикл сообщений. Это означает, что рабочая функция потока должна иметь цикл GetMessage/DispatchMessage. Если для обмена данными между потоками используются другие примитивы синхронизации, функция MsgWaitForMultipleObjects можно использовать для ожидания сообщений и событий синхронизации потоков. В документации по этой функции приведен пример этого цикла сочетания.
COM создает скрытое окно с помощью класса Windows OleMainThreadWndClass в каждой однопоточной квартире. Вызов объекта получается в виде сообщения окна в это скрытое окно. Когда квартира объекта извлекает и отправляет сообщение, скрытое окно получит его. Затем процедура окна вызовет соответствующий метод интерфейса объекта.
Когда несколько клиентов вызывают объект, вызовы помещаются в очередь сообщений, и объект будет получать вызов каждый раз, когда его квартира извлекает и отправляет сообщения. Так как вызовы синхронизируются com и вызовы всегда передаются потоком, принадлежащим к квартире объекта, реализации интерфейса объекта не должны обеспечивать синхронизацию. Однопоточные квартиры могут реализовать IMessageFilter, чтобы разрешить им отменять вызовы или получать сообщения окна при необходимости.
Объект можно повторно ввести, если одна из реализаций метода интерфейса извлекает и отправляет сообщения или выполняет вызов ORPC к другому потоку, что приводит к тому, что другой вызов будет доставлен в объект (по той же квартире). OLE не препятствует повторному входу в одном потоке, но может помочь обеспечить безопасность потока. Это идентично тому, как можно повторно ввести процедуру окна, если она извлекает и отправляет сообщения при обработке сообщения. Однако вызов внепроцессного однопоточного сервера квартиры, который вызывает другой однопоточный сервер квартиры, позволит повторно ввести первый сервер.
Связанные разделы