2014-12-21 7 views
1

Рассмотрим следующий сценарий:COM объект Срок службы

Этот код выполняется по нити A:

CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); 
globalSomeSTAComObject.CreateInstance((__uuidof(CLSID_SomeSTAComObject)); 
return 0; 

Теперь после того, как поток А делается это исполнение делает default STA «наследовать» globalSomeSTAComObject и он может быть использован другие темы?
Или этот объект становится непригодным?

Тот же вопрос относительно потока A, но теперь рассмотрим объект как объект MTA Com, который был создан в потоке MTA.
Когда поток А выполнен, выполняется ли объект MTA Com еще в пределах Multithreaded Apartment и может использоваться?

MSXML2::IXMLDOMDocumentPtr xml; 

unsigned __stdcall CreateXml(void*) 
{ 
    CoInitializeEx(nullptr, COINIT_MULTITHREADED); 
    xml.CreateInstance(__uuidof(MSXML2::FreeThreadedDOMDocument60)); 
    xml->load("c:\\test.xml"); 
    return 0; 
} 


int _tmain(int argc, _TCHAR* argv[]) 
{ 
    CoInitializeEx(nullptr, COINIT_MULTITHREADED); 
    HANDLE handle = reinterpret_cast<HANDLE>(_beginthreadex(nullptr, 0, CreateXml, nullptr, 0, nullptr)); 
    WaitForSingleObject(handle, INFINITE); 
    long numOfSections = xml->documentElement->childNodes->length; //This works why ? 
    xml.Release(); 
    CoUninitialize(); 
    return 0; 
} 

Пожалуйста, не в CreateXml я намеренно не называю CoUninitialize, потому что я хочу знать, что это состояние объекта XML в этом сценарии.

+1

Показанный снимок кода опасен. Не только вы не показываете, как вы собираетесь делать «CoUnitinialize», но вы также делаете определенные предположения об использовании специального указателя COM STA как для других потоков, так и после завершения STA/thread. 'globalSomeSTAComObject' может использоваться только в этом потоке и перед' CoUnitinialize'. Использование на других потоках может работать, но, как правило, неверно, и поведение не определено. –

+0

Если поток MTA создает объект MTA (глобальный объект) и завершается. Является ли объект еще «живым» в квартире MTA? Или в этом случае поведение не определено? – JobNick

+1

COM требует, чтобы вы прекратили свою деятельность COM перед вызовом 'CoUninitialize'. Следовательно, оставление COM-указателя вне этой инициализации неверно. Однако в случае MTA это гораздо менее частая проблема, поскольку указатель все еще действителен в присутствии любого другого потока MTA. В общем, вы иногда можете оставить COM-объект «просочившимся» из вспомогательного потока MTA, но суммируя все, я бы сказал, что вы все еще неправильно задаете свой вопрос. На первом месте есть что-то не так, пытаясь иметь объект singleton COM вне инициализации COM. –

ответ

0

Это зависит от моделей резьбы как самого COM-объекта, так и потока, который его создает.

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

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

Если объект имеет свободную резьбу, он будет находиться в STA, если он создан потоком STA, и будет жить в MTA, если он создан потоком MTA. Приведенные выше правила применяются.

Эта тема подробно обсуждается на MSDN:

Processes, Threads, and Apartments

Understanding and Using COM Threading Models

COM+ Threading Models

+0

Благодарим за ответ, но он не отвечает на мой вопрос относительно срока жизни объекта. Если поток STA создает объект STA и затем завершается, может ли доступ к объекту другим потокам? Тот же вопрос, но теперь поток MTA создает объект MTA, а затем завершает ли этот объект «живым» в квартире MTA и может быть доступен? – JobNick

+0

Срок службы объекта определяется его счетчиком ссылок, а не временем жизни потока, который его создал. Если вы прочитаете документацию, к которой я привязан, потоки и квартиры - это разные вещи. Нитки работают в квартирах, но они не создают и не владеют ими, COM делает. Итак, когда поток создает объект, его счетчик ссылок равен 1. Прежде чем поток завершится, он должен уменьшить счетчик ссылок объекта.Когда другие потоки обращаются к объекту, они должны увеличивать и уменьшать счетчик ссылок по мере необходимости. Когда счетчик ссылок падает до 0, объект освобождается. –

+0

Ну, я тестировал сценарии, о которых я говорил, и кажется, что в обоих из них после создания потока завершены объекты, которые все еще «живы» и доступны другим потокам, которые инициализировали COM. Мне было интересно, просто ли это случайность или это поведение по дизайну? – JobNick

0

COM-объект живет до тех пор, как он думает, что есть ссылки на него, т.е. счетчик ссылок больше нуля. Все перекрестные ссылки на объекты квартиры освобождаются при вызове CoUninitialize. Выпуски выпущены, уменьшая фактические значения фактических объектов. Простые прокси-серверы уведомляются и терпят неудачу при любых перерасчетах, возвращая RPC-ошибку HRESULT.

Однако я считаю, что выход из потока без необходимых вызовов на CoUninitialize не указал поведение. Я вижу сценарий, когда ничего не происходит, поэтому вы можете закончить, например, устаревшие ссылки на объекты STA, которые никогда не будут выполняться, поскольку вы вытаскиваете под ним ковер (поток) или мертвые объекты MTA, которые будут ошибочными, если не работает ни один поток MTA. Другим сценарием является то, что OLE32.dll обнаруживает это в своем DllMain по адресу DLL_THREAD_DETACH и все равно выполняет необходимую очистку, что приводит к некорректной ошибке при последующем вызове метода прокси.

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

Помните, что могут существовать несколько STA, и ни один объект STA никогда не переключает свою квартиру из-за самого COM, только если, возвратив прямой указатель интерфейса без маршалинга. Таким образом, когда STA умирает, его объекты не «принимаются» существующей или будущей STA, даже не основной (первая STA) или по умолчанию (созданной по необходимости самим COM), что может быть одна и та же.

Кроме того, после создания MTA каждый новый поток принадлежит MTA неявно, если явно не инициализирован при первом использовании COM. Однако такие потоки не поддерживают MTA.


P.S: Я прочитал из ваших комментариев, что ваш объект MTA является фактически свободным файлом. В этом нет никакой разницы, поскольку объект с бесплатной резьбой обойдется в процессе маршалинга, поэтому они будут принадлежать тому, что на самом деле создает их квартира, его методы работают во всех существующих квартирах, и они должны быть готовы как для многопоточности, так и для реентерации в модальных Шлюзы сообщений Windows из-за межсетевых, неблокирующих вызовов от STA.

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