Сегодня я написал сервер именованных каналов, используя порты IOCompletion, просто чтобы посмотреть, как.
Основной логический поток был:
- Я создал первый именованный канал через CreateNamedPipe
- Я создал основной объект Io Completion Port, используя этот дескриптор: CreateIoCompletionPort
- Я создаю пул рабочих потоков - как большой палец, ЦП х2. Каждый рабочий поток вызывает цикл GetQueuedCompletionStatus.
- Затем вызывается ConnectNamedPipe, передавая в перекрывающейся структуре. Когда этот канал подключится, один из вызовов GetQueuedCompletionStatus вернется.
- Мой основной поток затем присоединяется к пулу рабочих, также вызывая GetQueuedCompletionStatus.
Это действительно так.
Каждый раз, когда поток возвращает из GetQueuedCompletionStatus его, потому что связанный канал был подключен, прочитал данные или был закрыт.
Каждый раз, когда канал подключен, я немедленно создаю неподключенный канал для приема следующего клиента (вероятно, должно быть более одного ожидания одновременно) и вызываю ReadFile для текущего канала, передавая перекрывающуюся структуру - гарантируя, что при получении данных GetQueuedCompletionStatus расскажи мне об этом.
Есть несколько раздражающих крайних случаев, когда функции возвращают код ошибки, но GetLastError () является успешным. Поскольку функция «не удалась», вы должны обработать успех немедленно, так как статус завершения в очереди не был опубликован. И наоборот, (и я верю, что Vista добавляет API для «исправления» этого), если данные доступны немедленно, перекрывающиеся функции могут вернуть успех, но состояние завершения в очереди также публикуется, поэтому будьте осторожны, чтобы не обрабатывать данные в этом случае дважды.