FreeThreadedDOMDocument, Нейтральные Квартиры и Свободнопоточный Маршалер
Как говорится в MSDN:
Если вы пишете однопоточное приложение (или многопоточное приложение, где только один поток обращается к DOM одновременно), используйте арендуемую поточную модель (Msxml2.DOMDocument.3.0 или Msxml2.DOMDocument.6.0). Если вы пишете приложение, в котором многопотоковый доступ будет одновременно обращаться к DOM, используйте свободную потоковую модель (Msxml2.FreeThreadedDOMDocument.3.0 или Msxml2.FreeThreadedDOMDocument.6.0).
Есть ли какая-то связь между FreeThreadedDOMDocument, нейтральными квартирами и маршалером со свободной резьбой? Я заглянул в OleView и обнаружил, что модель потоков FreeThreadedDOMDocument - это Обе. Насколько я понимаю, нейтральные квартирные объекты поддерживаются маршалером со свободной резьбой. Означает ли это, что FreeThreadedDOMDocument не использует маршалер со свободным потоком, и это называется немного запутанным как свободный поток?
В чем разница между классами COM, помеченными как свободные, оба или нейтральные? Насколько я понимаю, все они должны быть поточно-ориентированными, в чем разница? Правильно ли, что Neutral должен поддерживать маршалер со свободной резьбой?
1 ответ
Здесь есть несколько вопросов.
TL; DR:
Нейтральные объекты:
- Выполнение маршалинга в процессе немного меньше, чем у объектов STA и MTA
- Избегайте переключения потоков
- Указатели интерфейса автоматически маршалируются
- Нейтральная квартира живет до тех пор, пока жив нейтральный объект
- Должен быть готов к запуску в любом потоке, используя функции COM для ожидания или выбрав функцию ожидания Win32 для использования в зависимости от типа потока
Свободные объекты с резьбой:
- Практически нет маршалинга в процессе
- Избегайте переключения потоков
- Указатели интерфейса не маршалируются автоматически
- Время жизни привязано к активации квартиры
- Должен быть готов к запуску в любом потоке, используя функции COM для ожидания или выбрав функцию ожидания Win32 для использования в зависимости от типа потока
Есть ли какая-то связь между FreeThreadedDOMDocument, нейтральными квартирами и маршалером со свободной резьбой?
TL; DR: FreeThreadedDOMDocument
Модель потоков - "Оба", поэтому она привязана к квартире, где она активирована (создана). Он объединяет бесплатный многопоточный маршалер, поэтому он является свободным многопоточным объектом.
FreeThreadedDOMDocument
это COM-класс, чьи объекты объединяют маршалер со свободным потоком Что этот маршалер делает, так это обеспечивает необработанный указатель при маршалинге в процессе (т.е. IMarshal::MarshalInterface
с dwDestContext
установлен в MSHCTX_INPROC
,
Я буду использовать определение свободного потокового объекта как объекта, который объединяет свободный потоковый маршалер.
Модель многопотоковых потоковых объектов должна быть указана как "Нейтральная" или "Оба" до Windows 2000, чтобы ее можно было создавать и использовать в любом потоке, избегая переключений контекста.
Если его потоковая модель указана как "Оба", время жизни объекта привязывается к квартире, в которой он был создан. Например, если поток STA завершается, все свободные потоковые объекты, созданные в этой квартире, либо уничтожаются, либо перестают действовать.
Насколько я понимаю, нейтральные квартирные объекты поддерживаются маршалером со свободной резьбой.
Нет, прокси для нейтральных объектов немного легче, чем другие прокси в процессе, поскольку он только устанавливает контекст COM, но он никогда не влечет за собой полное маршалинг и избегает переключения потоков.
Означает ли это, что FreeThreadedDOMDocument не использует маршалер со свободным потоком, и это называется немного запутанным как свободный поток?
Нет, FreeThreadedDOMDocument
действительно использует бесплатный резьбовой маршалер.
Исторически уже существовали бесплатные объекты с резьбой, прежде чем Microsoft предоставила им свою собственную поддержку (из-за популярности и, вероятно, потому, что большинство бесплатных потоковых маршалеров там были нестабильны), а квартира Neutral появилась только в Windows 2000.
Как таковые, случаи FreeThreadedDOMDocument
являются свободными нитями, потому что они объединяют маршалер со свободными нитями, а время жизни каждого экземпляра привязано к квартире, в которой он был создан. Обычно это мало влияет, но, например, с помощью пула потоков STA, эффект наблюдается чаще, потому что STA приходят и уходят по мере того, как потоки-владельцы заканчивают работу (обычно или для восстановления ресурсов) и создаются. Например, классический ASP по умолчанию использует потоки STA.
PS: я упомянул следующую тему в другом ответе, но я считаю, что содержание немного отличается, так как вопросы тоже разные.
Вот текущие значения модели потоков:
- Нет: используйте основной STA
- "Квартира": используйте любую STA, т. Е. Если текущая квартира является STA или NA, а не STA, используйте текущую STA, в противном случае используйте хост- STA (подробнее об этом позже)
- "Бесплатно": используйте MTA
- "Оба": использовать текущую квартиру
- "Нейтральный": используйте НС
Для любой квартиры, которая не существует, COM создает ее при необходимости.
Здесь есть несколько особенностей:
- Чтобы использовать основной STA, вы не должны упоминать какую-либо модель потоков, вместо чего-то более разумного, например, "Main".
- Все названия, кроме "Нейтрального", в настоящее время не имеют смысла:
- "Квартира" чувствует себя как текущая квартира, но это не так
- "Свободный" ощущается как свободные объекты с резьбой, но это не так
- "Оба" заставляют вас думать, что есть только 2 типа квартир, но есть 3: STA, MTA и NA
- На самом деле, начиная с Windows 8, существует ASTA, разновидность STA, созданная для графического интерфейса, которая во время исходящих вызовов отбрасывает входящие вызовы , которые не связаны, таким образом избегая большого источника ошибок повторного входа
- Вы можете заставить обычный STA вести себя так с фильтром сообщений
Основной STA - это первый созданный STA. Это имеет значение только для классов с неопределенной моделью потоков.
Может быть несколько STA, но не более одного MTA и одного NA.
Пока существует активный MTA, любой поток, не инициализированный для COM, неявно находится в MTA, если он не вызывает CoInitializeEx(NULL, COINIT_MULTITHREADED)
, но это также никак не влияет на время жизни MTA, означая, что MTA может быть уничтожен во время его использования потоком. Так как это вряд ли задокументировано и в значительной степени ненадежно, вы не должны полагаться на это.
Неявно созданные квартиры называются принимающей STA и принимающей MTA. Вы не можете их контролировать (разве что обманываете CoUninitialize
находясь в той квартире; примечание: на самом деле не делайте этого). Фактически, если вы активируете объекты "Квартира" вне STA или вне NA, работающего через STA, это будет активировано в хосте STA. Для дальнейшей путаницы это также может быть основной STA, если хост-STA была первой STA, которая должна быть инициализирована.
Все COM-потоки, которые поддерживают хост-квартиры, являются фоновыми, поэтому они не мешают вашему приложению завершиться.
Вы не имеете никакого контроля над АН, кроме как создавать его при активации нейтрального объекта. Вы не можете ввести его напрямую, но вы можете создать свой собственный нейтральный объект с помощью метода, который выполняет обратный вызов в контексте нейтральной квартиры. Этот обратный вызов может быть свободным потоком объекта.
В чем разница между классами COM, помеченными как свободные, оба или нейтральные?
Классы COM с квартирой, объявленной как "Свободная", приведут к объектам, которые принадлежат MTA. Такие объекты могут предполагать, что потоки, в которых они работают, не должны качать оконные сообщения. По сути, они могут блокировать.
Свободные объекты с резьбой и нейтральные объекты должны быть подготовлены для работы под любой квартирой. Для объектов со свободной резьбой должно быть очевидно почему: он обходит любой маршалинг контекста, поэтому методы выполняются в любом потоке. Для нейтральных объектов существует различие в том, какая квартира была активной (через CoGetApartmentType
).
В любом случае вы должны использовать служебные функции COM, такие как CoWaitForMultipleHandles
вместо WaitForMultipleHandles
[
Ex
]
который блокирует и недопустим в STA, или MsgWaitForMultipleHandles
[
Ex
]
, который обращается к очереди сообщений окна, вероятно, создавая ее неявно, и обычно неприемлемо в MTA.
Вы можете проверить тип квартиры самостоятельно и выбрать использование соответствующих функций ожидания Win32 или использовать стратегию опроса, которая ожидает и нагнетает сообщения с таймаутами в STA, в случае, если вы ожидаете что-то, кроме дескрипторов, или если вам требуется конкретная логика ожидания.
Самым поразительным отличием между объектами со свободной резьбой и нейтральными объектами является маршалинг других объектов COM.
При использовании нейтральных объектов входящие и исходящие указатели интерфейса автоматически маршалируются. Например, вы можете хранить входящие указатели интерфейса в полях.
При использовании объектов с бесплатной резьбой входящие и исходящие указатели интерфейса вообще не маршалируются, а это означает, что вы либо получаете необработанные указатели на объекты в той же квартире, либо вы получаете прокси на объекты в других квартирах. Эти прокси тоже привязаны к текущей квартире.
Например, входящий необработанный указатель означает, что вы получаете объект, который принадлежит текущей квартире, поэтому вам придется упорядочить его, если вы намереваетесь сохранить ссылку на объект.
Входящий прокси означает, что вы получаете прокси для объекта в другой квартире, но этот прокси привязан к текущей квартире. Вы также не можете хранить этот прокси. В частности, несмотря на проверку квартиры стандартных прокси / заглушек, прокси-серверы STA могут иметь сходство потоков. Вы должны также упорядочить это. Но не волнуйтесь, маршалинг прокси не будет составлять маршалинг; когда вы снова демаршируете, вы получите прокси для объекта, а не прокси для прокси.
Когда объект с свободной резьбой должен хранить указатель интерфейса, он всегда должен делать это с помощью ручного маршалинга, а когда он должен вызывать методы из этого указателя интерфейса, он должен делать это с помощью ручного демарширования.
Обычно для этой цели используется глобальная интерфейсная таблица (GIT; другое вводящее в заблуждение имя, фактически это таблица в процессе).
Насколько я понимаю, все они должны быть поточно-ориентированными, в чем разница?
Что касается безопасности потоков, нет никакой разницы.
Но, как я объяснил в предыдущем вопросе, существует огромная разница при хранении указателей на интерфейсы и тонкая разница в отношении активации объекта и срока его службы.
Правильно ли, что Neutral должен поддерживать маршалер со свободной резьбой?
Свободнопоточный маршалер эффективно игнорирует квартиру, поэтому ответственность за правильное поведение, синхронизацию и / или блокировку лежит на методах. Таким образом, ни одна квартира не должна поддерживать бесплатный резьбовой маршалер, это свободный объект с резьбой, который должен поддерживать каждую квартиру.
Свободный многопоточный маршалер можно объединять в объекты с любой моделью потоков, включая "Нейтральный".
Если вы обнаружите, что настройка контекста нейтральным маршалером квартиры является каким-то узким местом, то вы можете рассмотреть вопрос о том, чтобы использовать маршалер с бесплатными потоками за счет ручного маршалинга хранимых указателей интерфейса. Если нет, просто используйте нейтральную квартиру.