Singleton и Unlock
От: Staski  
Дата: 26.01.05 17:09
Оценка:
Проблема возникла. Имеем стандартный Singleton, сгенерированный визардом ATL.

Имеем метод
LONG CExeModule::Unlock()
{
LONG l = CComModule::Unlock();
if (l == 0)
{
bActivity = true;
BOOL b = SetEvent(hEventShutdown); // tell monitor that we transitioned to zero
}
return l;
}

Проблема в том, что данный метод вызывается два раза со значение (l == 0) и происходит падение (только на WINDOWS Server 2003) при втором вызове так как hEventShutdown уже закрыт.

Т.е. я в отдельном процессе пишу следующий код:
IUnknown* ptr2;
HRESULT hRes = ::CoCreateInstance(CLSID_STObj, NULL, CLSCTX_LOCAL_SERVER, IID_IUnknown, (void**)&ptr2);
ptr2->Release();

После вызова ptr2->Release() в Singleton вызывается Unlock(), счетчик блокировок становится равным 0, посылаетсыя эвент монитору. Казалось бы все нормально завершается, но в _tWinMain() после цикла обработки событий стоит _Module.RevokeClassObjects() при вызове этого метода в итоге приходим к вызову CComClassFactorySingleton::FinalRelease(), в котором вызывается CoDisconnectObject(m_Obj.GetUnknown(), 0);

Так вот эта GetUnknown() вызывает последовательно CComObjectGlobal::AddRef() и Release(), которые в свою очередь вызывают _Module.Lock() и Unlock().

Но счетчик блокировок модуля уже был равен нулю! Как такое может быть?!
Re: Singleton и Unlock
От: Staski  
Дата: 27.01.05 11:03
Оценка:
Дополнение. Проблема возникает со стандартным ATL'ным exe'шником при добавлении одной-единственной строки в хидер
DECLARE_CLASSFACTORY_SINGLETON(CSTObj)

При этом вместо одной пары Lock/Unlock получаем следующий лог работы:

CExeModule::Lock() == 1
CExeModule::Lock() == 2
CExeModule::Lock() == 3
CExeModule::Lock() == 4
CExeModule::Unlock() == 3
CExeModule::Unlock() == 2
CExeModule::Unlock() == 1
CExeModule::Unlock() == 0
SetEvent(hEventShutdown), return value == 1, lasterror == 1008
RevokeClassObjects()
CExeModule::Lock() == 1
CExeModule::Unlock() == 0
SetEvent(hEventShutdown), return value == 0, lasterror == 6
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.