
Программирование_распределенных_систем / iocp2
.pdfHANDLE CreateIOCompletionPort( HANDLE FileHandle, HANDLE ExistingCompletionPort,
ULONG_PTR CompletionKey, DWORD NumberOfConcurrentThreads);
HANDLE iocp=CreateIoCompletionPort(INVALID_HANDLE_VALUE,0,0,0);
for(int i=1;i<=2;i++) { HANDLE hWorking=CreateThread(0,0, (LPTHREAD_START_ROUTINE)&WorkingThread,iocp,0,0); CloseHandle(hWorking); }
while(1) { SOCKET clientsock=WSAAccept(listensock,(sockaddr *)&clientaddr,&clientsize,0,0); ... }
CreateIoCompletionPort((HANDLE)clientsock,iocp,(ULONG_PTR)key,0);
BOOL GetQueuedCompletionStatus( HANDLE CompletionPort, LPDWORD lpNumberOfBytes, PULONG_PTR lpCompletionKey, LPOVERLAPPED *lpOverlapped, DWORD dwMilliseconds);
Здесь CompletionPort — хендл порта, к пулу которого следует подключиться; lpNumberOfBytes — указатель на переменнную, в которую запишется количество переданных байт в результате завершения операции (фактически это возвращаемое значение recv() и send() в синхронном режиме); lpCompletionKey — указатель на переменную, в которую запишется указатель на ключ завершения; lpOverlapped — указатель на OVERLAPPED, ассоциированную с этой IO-транзакцией; наконец, dwMilliseconds — время, на которое поток может уснуть в ожидании завершения какоголибо запроса. Если указать INFINITE, то будет ждать вечно.
void WorkingThread(HANDLE iocp) { while(1) { if(! GetQueuedCompletionStatus(iocp,&bytes,&key,&overlapped,INFINITE)) //ошибка порта break; if(!bytes) //0 означает что дескриптор файла закрыт, т.е. клиент отсоединился switch(key- >OpType) { ... } } }
Внутри switch'а вызываются новые асинхронные операции, которые будут обработаны при следующем прохождении цикла. Если мы не хотим, чтобы определенная операция по завершению не была передана в порт (например, когда нам не важен результат), можно использовать следующий трюк — установить первый бит поля OVERLAPPED.hEvent равным 1.