Будет ли маршалинг COM (когда-либо) необходим для объекта с обоими ThreadingModel?

StackOverflow https://stackoverflow.com/questions/19847555

Вопрос

Это вызвано еще один вопрос.

В частности, у меня есть находящийся в процессе COM-класс, который определен в Реестр CLSID как имеющий ThreadingModel из Both.

Наш процесс активирует этот объект с помощью CoCreateInstance (нет CoCreateInstanceEx, если это вообще имеет значение для встроенного DLL-сервера)

Учитывая потоковую модель Bothи учитывая правила, перечисленные в Документы:

Threading model of server | Apartment server is run in
------------------------------------------------------
Both                      | Same apartment as client

и учитывая то, что Ганс пишет в другом ответе:

...Маршалинг происходит, когда вызов клиента должен быть выполнен в другом потоке....может произойти, когда этого требует ThreadingModel, указанный в элементе comClass.Другими словами, когда COM-объект был создан в одном потоке, но вызывается в другом, а сервер не потокобезопасен.

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

Правильно ли это, даже если клиентский процесс выполняется как STA?

Это было полезно?

Решение

Да, может быть маршалинг.

Если клиент вашего класса COM работает в STA, и вы пытаетесь вызвать свой класс из другой квартиры, ему придется маршала в квартиру, в которой она была создана.

Ком терминология может быть действительно запутанной. Когда вы обращаетесь к «клиенту» в этом случае, вы действительно имеете в виду поток, а не на все приложение (как это означает).

Both Просто означает, что потоковая модель сервера соответствует клиенту, который экстремирует его. То есть, когда вы создаете создание своего класса, он берет на себя модель потока потока, на которой он был создан. Поскольку вы создаете экземпляр сервера в STA, ваш сервер будет использовать STA, что означает, что его можно использовать только в потоке, который его создал; Если другая ветка пытается вызвать его, она будет маршала в поток, на которой он был создан.

Другие советы

Я не могу не публиковать это, хотя это не прямой ответ на вопрос.

Есть блестящая статья MSKB из золотых веков Com: Информация: описания и работы моделей OLE потоков. Анкет Все еще там, и имеет всю соответствующую информацию. Дело в том, что вы не должны беспокоиться о том, есть ли маршалинг или нет, если вы следуете правилам. Анкет Просто зарегистрируйте свой объект как ThreadingModel=Both, объединить маршалер свободного нагрузки CoCreateFreeThreadedMarshaler, и быть сделанным. COM сделает маршалинг, если это необходимо, наилучшим образом. В зависимости от модели квартиры клиента, клиент -код может получить прямой указатель на ваш интерфейс, если он также следует за правилами.

Любой «инопланетный» интерфейс, который вы можете получить, когда будет вызван метод вашего интерфейса, будет действительным в области вызова, поскольку вы остаетесь в одном и том же потоке. Если вам не нужно хранить его, это все, что имеет значение.

Однако, если вам нужно кэшировать интерфейс «инопланетянина», правильным способом сделать это будет хранение его с помощью CoMarshalInterThreadInterfaceInStream/CoGetInterfaceAndReleaseStream:

Чтобы хранить это:

  • Введите критический раздел;
  • вызов CoMarshalInterThreadInterfaceInStream и хранить IStream указатель в поле участника;
  • Оставить критический раздел;

Чтобы получить это

  • Введите критический раздел;
  • вызов CoGetInterfaceAndReleaseStream Чтобы получить интерфейс
  • вызов CoMarshalInterThreadInterfaceInStream и хранить его снова как IStream Для любого будущего использования
  • Оставить критический раздел;
  • Используйте интерфейс в области текущего вызова

Чтобы освободить:

  • Когда вам больше не нужно сохранять его, просто отпустите сохранение IStream (Внутри критического раздела).

Если объект «инопланетянина» тоже свободно нагружен, а вещи происходят в том же процессе, вы, вероятно, будете иметь дело с прямым указателем интерфейса после CoGetInterfaceAndReleaseStream. Анкет Тем не менее, вы не должны делать никаких предположений, и вам действительно не нужно знать, является ли объект, с которым вы работаете, является оригинальным объектом или прокси -сервером Com Marshaller.

Это может быть слегка оптимизировано с помощью CoMarshalInterface w/ MSHLFLAGS_TABLESTRONG / CoUnmarshalInterface / IStream::Seek(0, 0) / CoReleaseMarshalData вместо CoGetInterfaceAndReleaseStream/CoGetInterfaceAndReleaseStream, чтобы не считать тот же интерфейс столько раз, сколько необходимо, не выпустив поток.

Возможны более сложные (и, возможно, более эффективные) сценарии кэширования, включающие ниточное локальное хранение. Тем не менее, я считаю, что это будет излишним. Я не делал времени, но я думаю, что накладные расходы CoMarshalInterThreadInterfaceInStream/CoGetInterfaceAndReleaseStreamдействительно низкий.

Тем не менее, если вам нужно поддерживать состояние, которое хранит любые ресурсы или объекты, которые могут потребовать сродства потока, кроме вышеупомянутых интерфейсов COM, вы не должна Отметьте свой объект как ThreadingModel=Both или объединить FTM.

Да, маршаллинг все еще возможен. Пара примеров:

  1. Объект создается из резьбы MTA и таким образом помещается в квартиру MTA, а затем его указатель передается в любой поток STA, и что поток STA вызывает методы объекта. В этом случае поток STA может получить доступ к объекту только через Marshalling.

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

На самом деле вы не можете ожидать никакого маршалирования только в следующих двух случаях:

  1. Объект создается из потока MTA, а затем доступ к потокам MTA - как тот, который создал создание объекта и все другие потоки MTA того же процесса.
  2. Объект создается из потока STA, а затем доступен только по этому самым потоке

И во всех других случаях Marshalling начнется.

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

Таким образом, если экземпляр сервера был создан в STA, то клиентский программист будет ожидать, что события будут выполняться в том же потоке.Даже если серверный метод, который запускает такое событие, был вызван из другого потока.Для этого требуется, чтобы этот вызов был маршалирован.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top