2013-11-07 7 views
4

Это вызвано another question.Будет ли COM-маршаллинг быть (когда-либо) необходимым для объекта с ThreadingModel Оба?

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

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

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

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

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

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

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

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

+0

Ах. Возможный дубликат: http://stackoverflow.com/questions/3460071/does-it-require-to-marshal-the-com-object-supporting-threading-model-both?rq=1 –

ответ

6

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

Если клиент вашего COM класса работает в ГНА и вы пытаетесь вызвать свой класс из другой квартиры, он должен будет мобилизовывать в квартиру, что он был создан.

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

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

+0

... и если вы не нужно также маршировать в этом случае, а затем пометить свой объект ThreadingModel = Both, а также объединить произвольный маршалер (иначе FTS, см. 'CoCreateFreeThreadedMarshaler'). Будьте осторожны - такой объект в значительной степени не может кэшировать любые указатели интерфейса (или любое другое аффинное состояние квартиры), если только они, как известно, также не объединяют FTS. –

+0

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

+0

Итак, если клиентский поток инициализирован MTA, не будет никакого сортировки? И если клиент потока STA является единственным потоком для вызова в объект, также не будет никакого сортировки? –

2

Да, сортировка по-прежнему возможна. Несколько примеров:

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

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

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

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

и во всех остальных случаях сортировочных будет удар в.

+0

"... тогда его указатель передается в любой поток STA ...": Я считал незаконным передавать указатель объекта на другую квартиру? –

+0

В частности, [вы пишете в другом ответе] (http://stackoverflow.com/a/3465006/321013), что «... Если вы просто передаете необработанный указатель, тогда нет средств для включения маршаллинга ...», и я понимаю, что, если наш код не содержит явные вызовы маршаллинга для указателей объектов, мы могли бы случайно передать неоновые указатели в другую квартиру, но это было бы незаконно. –

3

Я не могу помочь себе отправляю это, хотя он не является прямым ответом на вопрос.

Существует блестящая статья MSKB от золотых веков COM: INFO: Descriptions and Workings of OLE Threading Models. Все еще есть и имеет всю необходимую информацию. Дело в том, что вы не должны беспокоиться о том, есть ли маршалинг или нет, если вы следуете правилам. Просто зарегистрируйте свой объект как ThreadingModel=Both, соберите Free-Threaded Marshaler с CoCreateFreeThreadedMarshaler и сделайте это. COM будет делать маршалинг, если необходимо, наилучшим образом. В зависимости от модели квартиры клиента код клиента может получать прямой указатель на ваш интерфейс, если он также следует правилам.

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

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

Чтобы сохранить его:

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

Чтобы получить его

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

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

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

Если «чужой» объект свободен нарезка тоже, и все происходит в том же процессе, вы, вероятно, будете иметь дело с прямым указателем интерфейса после CoGetInterfaceAndReleaseStream. Однако вы не должны делать каких-либо предположений, и вам действительно не нужно знать, является ли объект, с которым вы работаете, оригинальным объектом или прокси-сервером COM-маршаллера.

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

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

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

1

ThreadingModel = Both просто означает, что автор COM-сервер может дать гарантию, что его код потокобезопасно, но не может дать такую ​​же гарантию, что другой код он не написал будет называться в поточно-образом , Наиболее распространенным случаем получения такого внешнего кода является обратный вызов, точки подключения - наиболее распространенный пример (обычно называемый «событиями» во время выполнения клиента).

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

 Смежные вопросы

  • Нет связанных вопросов^_^