One more thing that's very good about IOCP is that it can manage the number of threads running so you don't have to waste context switches and it tries to maximize the the workd made by the threads, instead of wasting processor time context switching between them.
Yes, that's one thing i find interesting about it and i actually like the way it works. It should scale very nicely with the number of CPUs (cores) on machines.
we did take a look at SOAP like Taby said but considering the nature of what we're doing, it is not really appropriate. Don't get me wrong, those tools are really neat. I'll take a look at non-boost asio.
I have work on a small prototype and encontered a weird problem with my I/O worker threads. The server thread basically waits on an event that is triggered when a connection is received, her's the code for the thread routine :
int AsyncServer::Run()
{
bool bRunning = true;
DWORD iRet = 0;
HANDLE Events[SE_COUNT] = {0};
if(mIocp.Create(miConcurency))
{
if(mIoWorker.Initialize(&mIocp))
{
Events[SE_ACCEPT_EVENT] = mhAcceptEvent;
Events[SE_SHUTDOWN_EVENT] = mhShutdownEvent;
// Reset the shutdown event.
ResetEvent(mhShutdownEvent);
if(CreateListeningSocket(BACKLOG_COUNT))
{
if(WSAEventSelect(mListener, mhAcceptEvent, FD_ACCEPT) != SOCKET_ERROR)
{
while(bRunning)
{
DWORD iWaitResult = WaitForMultipleObjects(SE_COUNT, Events, FALSE, INFINITE);
switch(iWaitResult)
{
case WAIT_OBJECT_0:
{
ResetEvent(mhAcceptEvent);
//TEST
struct sockaddr_in remote = {0};
int iAddrLen = sizeof(remote);
DESCRIPTOR Socket = WSAAccept(mListener,
reinterpret_cast<struct sockaddr *>(&remote),
&iAddrLen,
NULL,
NULL);
closesocket(Socket);
TRACE(L"\n--- Accepted connection ---\n");
//END TEST
}
break;
case (WAIT_OBJECT_0 + 1):
{
// Shutdown the server.
bRunning = false;
//TEST
TRACE(L"\n--- Server shutting down ---\n\n");
//END TEST
}
break;
}
}
}
}
// Server shutdown.
ShotdownSequence();
}
}
return 0;
}
The mIoWorker.Initialize does this :
bool bRetVal = true;
IOWorker *pWorker = NULL;
unsigned int iThreadCount = pIocp->GetConcurrentThreadCount();
mpIocp = pIocp;
mWorkers.reserve(iThreadCount);
for(unsigned int i = 0; i < iThreadCount; ++i)
{
pWorker = new(std::nothrow) IOWorker(pIocp);
if(pWorker)
{
mWorkers.push_back(pWorker);
bRetVal = bRetVal && pWorker->Start();
}
}
return bRetVal;
So, in order to stop the thread, the mhShutdownEvent event is signaled which breaks the loop and gets to the ShotdownSequence method. The method called to stop the server basically only signal the event then calls WaitForSingleObject on the thread handle.
The ShotdownSequence() method does the following :
void AsyncServer::ShotdownSequence()
{
// Shutdown the I/O thread pool.
mIoWorker.Shutdown();
// Close the iocp.
mIocp.Close();
mbIsRunning = false;
}
and mIoWorker.Shutdown() post a completion packet for each thread and waits for each thread to terminate :
void IOWorkerPool::Shutdown()
{
IOWorker *pWorker = NULL;
std::vector<IOWorker *>::iterator it;
for(unsigned int i = 0; i < mWorkers.size(); ++i)
{
mpIocp->PostIoCompletionOperation(NULL);
}
for(unsigned int i = 0; i < mWorkers.size(); ++i)
{
mWorkers[i]->Wait();
}
while(mWorkers.size())
{
pWorker = (*mWorkers.begin());
delete pWorker;
mWorkers.erase(mWorkers.begin());
}
pWorker = NULL;
}
The problem i have with this is that it freezes once in a while waiting on a thread (ramdom one) when it shutsdown. However, the threads all terminate normaly. If i put a Sleep(2000) as a test instead of the loop that calls mWorkers[i]->Wait(), everything terminate just fine (Sleep is just for a test). The wait method simply calls WaitForSingleObject on the thread handle. I really don't see what happens ....
The I/O workers only do the following so far :
int IOWorker::Run()
{
DWORD iBytes = 0;
ConnectionLink *pLink = NULL;
LPOVERLAPPED pOverlapped = NULL;
while(mbIsRunning)
{
if(mpIocp->GetIoCompletionOperation(&iBytes, &pLink, &pOverlapped))
{
if(pLink)
{
}
else
{
mbIsRunning = false;
}
}
}
return 0;
}
Edit :
Is it wrong to use WaitForSingleObject to wait for a thread to terminate (or at least to call it many times in row) ?
Edited by Laval B, 22 May 2012 - 10:43 AM.