Now that we have a suitable thread pool we can integrate it with our fake POP3 socket server so that the actual processing of commands can occur in the business logic pool whilst the IO pool is left to get on with the IO operations. We can also move socket closure off to the business logic pool so that we don't block the IO threads with a lingering socket close.
The first thing we need to do is create and configure our thread pool. Then we can pass a reference to it to our socket server class so that it can pass a reference to it to our IO threads.
CThreadPool pool(
5, // initial number of threads to create
5, // minimum number of threads to keep in the pool
10, // maximum number of threads in the pool
5, // maximum number of "dormant" threads
5000, // pool maintenance period (millis)
100, // dispatch timeout (millis)
10000); // dispatch timeout for when pool is at max threads
pool.Start();
CSocketServer server(
INADDR_ANY, // address to listen on
5001, // port to listen on
10, // max number of sockets to keep in the pool
10, // max number of buffers to keep in the pool
1024, // buffer size
pool);
server.Start();
When our socket server has a complete, distinct, message to process it can dispatch it to the thread pool for processing, rather than processing it on one of its IO threads.
void CSocketServer::ProcessCommand(
CSocketServer::Socket *pSocket,
CIOBuffer *pBuffer)
{
pSocket->AddRef();
pBuffer->AddRef();
m_pool.Dispatch(reinterpret_cast(pSocket), 0, pBuffer->GetAsOverlapped());
}
Since we're passing the socket and IO buffer to another thread we have to increment their reference counts so that they dont get cleared up from underneath us. Over in our business logic thread we can finally process the message, and then release the references we took on the socket and IO buffer.
void CThreadPoolWorkerThread::Process(
ULONG_PTR completionKey,
DWORD operation,
OVERLAPPED *pOverlapped)
{
Socket *pSocket = reinterpret_cast(completionKey);
CIOBuffer *pBuffer = CIOBuffer::FromOverlapped(pOverlapped);
ProcessMessage(pSocket, pBuffer);
pSocket->Release();
pBuffer->Release();
}
Since the socket class marshals all IO requests back to the IO thread pool we can safely make read and write requests from our business logic thread even though the thread may be terminated before the IO requests completes.
Comments