Делаю приложение на IOCP. Заметил, что после подключения и отключения клиентов количество дескрипторов (в диспетчере задач) не возвращается к первоначальному. Упростил всю логику до предела. Ниже полный код класса, при работе которого видна утечка хэндлов. Это демка, упрощенная до нельзя. Буду очень благодарен, если вы попробуете собрать проект у себя и выскажете свои мысли. Делаем пустой консольный проект с поддержкой mfc, в _tmain создаем экземпляр класса, вызываем метод Start. Нужна помощь. У кого какие мысли?
header
Код:
#include "Mutex.h"
typedef struct
{
void * m_This;
int m_ThreadNumber;
}TIOCPParams;
typedef struct
{
OVERLAPPED m_ovrl;
SOCKET m_sock;
}TMYOVERLAPPED;
class CD2Class
{
public:
int IOCPThread(TIOCPParams * pParams);
int Stop();
int Start();
CD2Class();
virtual ~CD2Class();
HANDLE m_threadEvent;
HANDLE m_hIocp;
CMutex m_Mutex;
int m_stop;
int m_opcnt;
};
source
Код:
int gIOCPThread(void * pParams)
{
TIOCPParams ThreadParams = *(TIOCPParams *)pParams;
CD2Class * pD2 = (CD2Class *)ThreadParams.m_This;
return pD2->IOCPThread( &ThreadParams );
}
CD2Class::CD2Class() : m_Mutex(0)
{
m_stop = 0;
m_hIocp = NULL;
m_threadEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
m_opcnt = 0;
}
CD2Class::~CD2Class()
{
CloseHandle( m_threadEvent );
}
int CD2Class::Start()
{
int i, nRet = 0, threads = 1, cnt = 0;
struct sockaddr_in addr;
WSAData wsData;
SYSTEM_INFO si;
struct sockaddr_in clientaddr;
int length = sizeof(clientaddr);
ULONG lngMode = 1;
TMYOVERLAPPED * pOvrl = NULL;
SOCKET listensocket, clientsocket;
int blnBindLocal = 1;
WORD port = 5001;
m_stop = 0;
/////////////////////////////
GetSystemInfo(&si);
/////////////////////////////
if( (nRet = WSAStartup( MAKEWORD(2, 2), &wsData )) < 0 ) {
return false;
}
if ( (listensocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET) {
return false;
}
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = (blnBindLocal) ? inet_addr("127.0.0.1") : htonl(INADDR_ANY);
if ( (nRet = bind( listensocket, (struct sockaddr *) &addr, sizeof(addr) )) < 0 ) {
closesocket (listensocket );
return false;
}
if ( (nRet = listen( listensocket, 100 )) < 0 ) {
closesocket (listensocket );
return false;
}
if ( (m_hIocp = ::CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, 0, 0 )) == NULL ) {
closesocket (listensocket );
return false;
}
/////////////////////////////////////////////////////////////////////////////////////////
threads = (si.dwNumberOfProcessors);
for(i=0;i<(int)threads;i++) {
TIOCPParams params;
CWinThread * pThread = NULL;
memset(¶ms, 0, sizeof(params));
ResetEvent(m_threadEvent);
params.m_This = this;
params.m_ThreadNumber = i;
pThread = AfxBeginThread((AFX_THREADPROC)gIOCPThread, ¶ms, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
pThread->m_bAutoDelete = true;
pThread->ResumeThread();
Sleep(10);
WaitForSingleObject(m_threadEvent, INFINITE);
}
while( m_stop == 0 ) {
pOvrl = new TMYOVERLAPPED();
memset(pOvrl, 0, sizeof(*pOvrl));
if ( (pOvrl->m_sock = accept(listensocket, (struct sockaddr *)&clientaddr, &length)) != INVALID_SOCKET ) {
m_Mutex.Lock();
m_opcnt++;
m_Mutex.Unlock();
printf("connection #%u\r\n", ++cnt);
if (ioctlsocket(pOvrl->m_sock, FIONBIO, (u_long FAR*) &lngMode) == SOCKET_ERROR ) {
closesocket( pOvrl->m_sock );
continue;
}
//CreateIoCompletionPort( (HANDLE)pOvrl->m_sock, m_hIocp, (ULONG)&pOvrl->m_sock, 0 );
if ( pOvrl != NULL ) {
PostQueuedCompletionStatus(m_hIocp, 1, NULL, (OVERLAPPED*)pOvrl);
}
}
};
return true;
}
int CD2Class::Stop()
{
WSACleanup();
CloseHandle(m_hIocp);
Sleep(100);
m_stop = 1;
return true;
}
int CD2Class::IOCPThread(TIOCPParams * pParams)
{
int nRet = 0, localstop = 0;
void * pKey;
TMYOVERLAPPED * pOvrl;
DWORD dwBytesTransferred;
DWORD error;
TIOCPParams params = *pParams;
SetEvent(m_threadEvent);
Sleep(10);
while ( ( m_stop == 0 ) && (localstop == 0) )
{
pKey = NULL;
pOvrl = NULL;
nRet = GetQueuedCompletionStatus(m_hIocp, &dwBytesTransferred, (ULONG*)&pKey, (OVERLAPPED **)&pOvrl, 5000);
if(nRet == 0) {
error = GetLastError();
if( error == WAIT_TIMEOUT ) {
printf("thread #%u\r\n", params.m_ThreadNumber + 1);
continue;
}
if ( pOvrl == NULL )
continue;
}
if (pOvrl->m_ovrl.hEvent != 0) {
m_stop = m_stop;
}
//CloseHandle( (HANDLE)pOvrl->m_sock );
closesocket( pOvrl->m_sock );
delete pOvrl;
m_Mutex.Lock();
m_opcnt--;
m_Mutex.Unlock();
};
return nRet;
}