Thread pool
Last week I find those cool code shared by Sherwood Hu. You can view the article named "A programming model to use a thread pool" for details of this class. I used this class to boot the performance of my application. But a strange phenomenon puzzled me for a long time. That is: it works perfectly when I run my application normally, but suspends sometimes when I debug my application. I located the bug finally after some "Ctrl+Alt+Del". Check the original code here:
unsigned int CThreadPool::ManagerProc(void* p)
{
CThreadPool* pServer=(CThreadPool*)p;
HANDLE IoPort = pServer->GetMgrIoPort();
unsigned long pN1, pN2;
OVERLAPPED* pOverLapped;
LABEL_MANAGER_PROCESSING:
while(::GetQueuedCompletionStatus(IoPort, &pN1, &pN2,
&pOverLapped, pServer->GetMgrWaitTime() ))
{
if(pOverLapped == (OVERLAPPED*)0xFFFFFFFF)
break;
else
{
TRACE0("mgr events comes in!\n");
}
}
if (::GetLastError()==WAIT_TIMEOUT)
{
TRACE0("Time out processing!\n");
if (pServer->GetThreadPoolStatus()==CThreadPool::BUSY)
pServer->AddThreads();
if (pServer->GetThreadPoolStatus()==CThreadPool::IDLE)
pServer->RemoveThreads();
goto LABEL_MANAGER_PROCESSING;
}
return 0;
}
The CThreadPool::Stop
function uses:
::PostQueuedCompletionStatus(m_hMgrIoPort, 0, 0, (OVERLAPPED*)0xFFFFFFFF);
to stop the manager thread. The manager thread uses:
::GetQueuedCompletionStatus(IoPort, &pN1, &pN2,
&pOverLapped, pServer->GetMgrWaitTime())
to wait this message. When it meets the condition:
pOverLapped == (OVERLAPPED*)0xFFFFFFFF)
the thread stops normal. While this API wait times out, it uses "goto" continue waiting. Quit message and timeout event may not occur if the program runs normally, but it may occur when you debug your code. The manager thread will receive the quit message and timeout event at the same time while you insert the break point in your code and trace it step by step. The manager thread receives the quit message and breaks from while
circulation, but is caught by the following if
statement and throw
to begin by "goto" statement. Since it will never receive quit message again, it will circulate endless. So the application will suspend at here:
void CThreadPool::Stop(bool bHash)
{
......
WaitForSingleObject(m_hMgrThread, INFINITE);
......
}
Solution
I add a sign to distinguish the quit message and timeout event, and thus the bug is fixed.
.....
BOOL bExit = FALSE;
LABEL_MANAGER_PROCESSING:
while(::GetQueuedCompletionStatus(IoPort, &pN1, &pN2,
&pOverLapped, pServer->GetMgrWaitTime() ))
{
if(pOverLapped == (OVERLAPPED*)0xFFFFFFFF)
{
bExit = TRUE;
break;
}
else
{
TRACE0("mgr events comes in!\n");
}
}
if (::GetLastError()==WAIT_TIMEOUT && !bExit)
{
......