Есть серверное приложение с кучей одинаковых потоков. В каждом потоке в начале вызывается CoInitialize, а в конце CoUninitialize. Сами потоки выполняют некоторые скрипты, где могут создаваться различные COM объекты. Изредка вызов CoUninitialize зависает и не даёт потоку нормально завершиться. При этом стек вызовов имеет такой вид:
Здравствуйте, Voinov, Вы писали:
V>Есть серверное приложение с кучей одинаковых потоков. В каждом потоке в начале вызывается CoInitialize, а в конце CoUninitialize. Сами потоки выполняют некоторые скрипты, где могут создаваться различные COM объекты. Изредка вызов CoUninitialize зависает и не даёт потоку нормально завершиться. При этом стек вызовов имеет такой вид:
V>... V># 0x7769174C, CreateErrorInfo+3085, <no source info>, ole32 V># 0x776BCE40, CoUninitialize+407, <no source info>, ole32 V># 0x776BCDF2, CoUninitialize+329, <no source info>, ole32 V># 0x00409AB1, ScriptThreadProc+577, scriptthread.cpp [.text+0x00008AB1] 94+0, surrogate
V>Т.е. оно зависает в каком-то Sleep, вызываемом из NdrEncapsulatedUnionMarshall. V>Сталкивался ли кто-нибудь с подобным и как это можно побороть?
Здравствуйте, Vi2, Вы писали:
Vi2>Здравствуйте, Voinov, Вы писали:
V>>Есть серверное приложение с кучей одинаковых потоков. В каждом потоке в начале вызывается CoInitialize, а в конце CoUninitialize. Сами потоки выполняют некоторые скрипты, где могут создаваться различные COM объекты. Изредка вызов CoUninitialize зависает и не даёт потоку нормально завершиться. При этом стек вызовов имеет такой вид:
V>>... V>># 0x7769174C, CreateErrorInfo+3085, <no source info>, ole32 V>># 0x776BCE40, CoUninitialize+407, <no source info>, ole32 V>># 0x776BCDF2, CoUninitialize+329, <no source info>, ole32 V>># 0x00409AB1, ScriptThreadProc+577, scriptthread.cpp [.text+0x00008AB1] 94+0, surrogate
V>>Т.е. оно зависает в каком-то Sleep, вызываемом из NdrEncapsulatedUnionMarshall. V>>Сталкивался ли кто-нибудь с подобным и как это можно побороть?
Vi2>Посмотри здесь решение Бага в CoUninitialize
Здравствуйте, Voinov, Вы писали:
V>Есть серверное приложение с кучей одинаковых потоков. В каждом потоке в начале вызывается CoInitialize, а в конце CoUninitialize. Сами потоки выполняют некоторые скрипты, где могут создаваться различные COM объекты. Изредка вызов CoUninitialize зависает и не даёт потоку нормально завершиться.
Покажи, пожалуйста, параметры инициализации COM в основном и рабочих потоках — там какая "потоковая" модель указывается?
А эти потоки работают строго со своим набором объектов, или они могут юзать/создавать COM-объекты разделяемые другими потоками? То есть поток создал объект, а потом его где-то на глобальном уровне приложения закэшировал для повторного использования. Такого нет?
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Здравствуйте, Igor_Sokolov, Вы писали:
I_S>А зачем, собственно, вообще может понадобиться вызывать CoUninitialize? I_S>просто интересуюсь — всегда игнорировал
"Typically, the COM library is initialized on a thread only once. Subsequent calls to CoInitialize or CoInitializeEx on the same thread will succeed, as long as they do not attempt to change the concurrency model, but will return S_FALSE. To close the COM library gracefully, each successful call to CoInitialize or CoInitializeEx, including those that return S_FALSE, must be balanced by a corresponding call to CoUninitialize. However, the first thread in the application that calls CoInitialize(0) or CoInitializeEx(COINIT_APARTMENTTHREADED) must be the last thread to call CoUninitialize(). If the call sequence is not in this order, then subsequent calls to CoInitialize on the STA will fail and the application will not work." (с) MSDN
"Как правило, библиотека COM инициализируется в потоке только один раз. Последующие вызовы CoInitialize или CoInitializeEx в том же потоке будут успешны, если они не будут пытаться изменить потоковую модель синхронизации СОМ, но с возвратом S_FALSE. Чтобы закрыть библиотеку COM правильно, каждый успешный вызов CoInitialize или CoInitializeEx, в том числе вернувший S_FALSE, должен быть уравновешен соответствующим вызовом CoUninitialize. Кроме того, первый поток в приложении, который вызывает CoInitialize(0) или CoInitializeEx(COINIT_APARTMENTTHREADED) должен быть последним потоком, вызвавшим CoUninitialize(). Если последовательность вызовов происходит не в таком порядке, то последующие вызовы CoInitialize на STA не будут успешны, и приложение не будет работать." (с) MSDN
Удовлетворять требованию парности любых скобок у программиста должно быть на уровне автоматизма, не дожидаясь внешних принуждений от кого бы то ни было.