aitForSingleObject exit for timeout only, thread is not signaled
Hello everybody,
I am working with a thread for implementing a timer. If the thread is started / exited directly from an application (standard exe) everything works fine, but if I create and exit it from within a DLL loaded by the application, WaitForSingleObject fails to detect the thread exit. Why is that?
WaitForSingleObject exits with WAIT_TIMEOUT after 5 seconds instead of WAIT_OBJECT_0 (the one that I expect) and then I am forced to kill the thread with
TerminateThread.
I used the scroll key LED and Dbgview (OutputDebugString) for debugging.
In case someone were so kind to help me I attached a sample Borland C++ Builder project with the code below (including a testing console for loading / unloading the DLL library).
Anyone can help?
Thank you very much in advance!!!!!!
Here is the code:
#include <windows.h>
#include <stdio.h>
HANDLE MyThreadHandle = NULL;
DWORD MyThreadId = 0;
bool MyThreadEnable = false;
void DebugMess(char *sMess)
{
char sDbg[257];
sprintf(sDbg, "PID=%04x,TID=%04x: %s", GetCurrentProcessId(), GetCurrentThreadId(), sMess);
OutputDebugString(sDbg);
}
DWORD WINAPI ThreadFunction(void *unused)
{
while (MyThreadEnable)
{
DebugMess("Thread running...");
keybd_event(VK_SCROLL, 0, 0, 0);
Sleep(500);
keybd_event(VK_SCROLL, 0, KEYEVENTF_KEYUP, 0);
Sleep(500);
}
return 0;
}
void ThreadCreate(void)
{
SECURITY_ATTRIBUTES saAttr;
if (MyThreadHandle == NULL)
{
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = true;
saAttr.lpSecurityDescriptor = NULL;
MyThreadHandle = CreateThread (
&saAttr ,
0 ,
ThreadFunction ,
(LPVOID) NULL ,
CREATE_SUSPENDED ,
&MyThreadId );
if (MyThreadHandle != NULL)
{
MyThreadEnable = true;
}
}
return;
}
void ThreadDestroy(void)
{
if (MyThreadHandle)
{
/* Exit from loop */
MyThreadEnable = false;
/* Wait thread exit */
switch (WaitForSingleObject(MyThreadHandle, 5000))
{
case WAIT_OBJECT_0 :
{
DebugMess("Thread ended OK");
break;
}
case WAIT_TIMEOUT :
{
DebugMess("WaitForSingleObject - timeout");
TerminateThread(MyThreadHandle, 0);
break;
}
default :
{
DebugMess("WaitForSingleObject - other");
TerminateThread(MyThreadHandle, 0);
break;
}
}
keybd_event(VK_SCROLL, 0, KEYEVENTF_KEYUP, 0);
CloseHandle(MyThreadHandle);
MyThreadHandle = NULL;
MyThreadId = 0;
}
}
void _DllTimerProcessAttach(void)
{
ThreadCreate();
if (MyThreadHandle)
{
ResumeThread(MyThreadHandle);
}
else
{
DebugMess("Thread creation failed");
}
}
void _DllTimerProcessDetach(void)
{
ThreadDestroy();
}
void _DllTimerThreadAttach(void)
{
}
void _DllTimerThreadDetach(void)
{
}
And the DllEntryPoint function:
#pragma argsused
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
int iDllProcess;
switch ( reason )
{
case DLL_THREAD_ATTACH :
{
_DllTimerThreadAttach();
iDllProcess = 1;
break;
}
case DLL_THREAD_DETACH :
{
_DllTimerThreadDetach();
iDllProcess = 1;
break;
}
case DLL_PROCESS_ATTACH :
{
_DllTimerProcessAttach();
iDllProcess = 1;
break;
}
case DLL_PROCESS_DETACH :
{
_DllTimerProcessDetach();
iDllProcess = 1;
break;
}
}
return ( iDllProcess );
}
1 Attachment(s)
Re: aitForSingleObject exit for timeout only, thread is not signaled
Your problem is: thread does not actually unload on kernel level until dll process detach completed. See the sample when ThreadDestroy is called before freeing library - the thread exit gets detected fine.
Re: WaitForSingleObject exit for timeout only, thread is not signaled
Igor,
thank you for your reply.
In your opinion, do you think there might be a clean solution relying only on FreeLibrary, i.e. doing everything that is needed to exit the thread and detect thread exit when the DLL is unloaded, or the only solution is telling the DLL user to call a specific DLL function before unloading the DLL with FreeLibrary?
Re: WaitForSingleObject exit for timeout only, thread is not signaled
Frankly, your sample is evidently artificial, and it's hard to say what exact scenario you do expect in a field. For example, I don't see any good in running the thread initially suspended and resume it anyway after a couple of CPU cycles. And the same way I do not understand why you should wait for thread quit. Is it just for paranoidly killing it? :)
On the other hand, in case this would be some SDK dll, it seems absolutely normal to instruct its user to (un)initialize it at a proper moment.