Объект loCompletion

Приложения используют объект loCompletion исполнительной системы, который экспортируется в Windows как порт завершения (completion port) — фокальная точка завершения ввода-вывода, сопоставляемая с множеством описателей файлов. Если какой-нибудь файл сопоставлен с портом завершения, то по окончании любой операции асинхронного ввода-вывода, связанной с этим файлом, в очередь порта завершения ставится пакет завершения (completion packet). Ожидание завершения любой из операций ввода-вывода в нескольких файлах может быть реализовано простым ожиданием соответствующего пакета завершения, который должен появиться в очереди порта завершения. Windows API поддерживает аналогичную функциональность через WaitForMultipleObjects, но порты завершения дают одно большое преимущество: число потоков, активно обслуживающих клиентские запросы, контролируется самой системой.

Создавая порт завершения, приложение указывает максимальное число сопоставленных с портом потоков, которые могут быть активны. Как уже говорилось, в идеале на каждом процессоре должно быть по одному активному потоку. Windows использует это значение для контроля числа актив ных потоков приложения. Если число активных потоков, сопоставленных с портом, равно заданному максимальному значению, выполнение потока, ждущего на порте завершения, запрещено. По завершении обработки текущего запроса один из активных потоков проверяет, имеется ли в очереди порта другой пакет. Если да, он просто извлекает этот пакет из очереди и переходит к обработке соответствующих данных; контекст при этом не переключается.

Использование портов завершения

Высокоуровневая схема работы порта завершения представлена на рис. 9-20. Порт завершения создается вызовом Windows-функции CreateIoCompletionPort. Потоки, блокированные на порте завершения, считаются сопоставленными с ним и пробуждаются по принципу LIFO («последним пришел — первым вышел»), т. е. следующий пакет достается потоку, заблокированному последним. Стеки потоков, блокируемых в течение длительного времени, могут быть выгружены в страничный файл. B итоге, если с портом сопоставлено больше потоков, чем нужно для обработки текущих заданий, система автоматически минимизирует объем памяти, занимаемой слишком долго блокируемыми потоками.

Серверное приложение обычно получает клиентские запросы через конечные точки, представляемые как описатели файлов. Пример — сокеты Windows Sockets 2 (Winsock2) или именованные каналы. Создавая конечные точки своих коммуникационных связей, сервер сопоставляет их с портом завершения, и серверные потоки ждут входящие запросы, вызывая для этого порта функцию GetQueuedCompletionStatus. Получив пакет из порта завершения, поток начинает обработку запроса и становится активным. B процессе обработки данных поток может часто блокироваться, например из-за необходимости считать данные из файла или записать их в него, а также из-за синхронизации с другими потоками. Windows обнаруживает такие действия и выясняет, что одним активным потоком на порте завершения стало меньше. Поэтому, как только поток блокируется и становится неактивным, операционная система пробуждает другой ждущий на порте завершения поток (если в очереди есть пакет).

Microsoft рекомендует устанавливать максимальное число активных потоков на порте завершения примерно равным числу процессоров в системе. Имейте в виду, что это значение может быть превышено. Допустим, вы задали, что максимальное значение должно быть равно 1. При поступлении клиентского запроса выделенный для его обработки поток становится активным. Поступает второй запрос, но второй поток не может продолжить его обработку, так как лимит уже достигнут. Затем первый поток блокируется в ожидании файлового ввода-вывода и становится неактивным. Тогда освобождается второй поток и, пока он активен, завершается файловый ввод-вывод для первого потока, в результате чего первый поток вновь активизируется. C этого момента и до блокировки одного из потоков число активных потоков превышает установленный лимит на 1.

API, предусмотренный для порта завершения, также позволяет серверному приложению ставить в очередь порта завершения самостоятельно определенные пакеты завершения; для этого предназначена функция PostQueuedCompletionStatus. Сервер обычно использует эту функцию для уведомления своих потоков о внешних событиях, например о необходимости корректного завершения работы.


Логин
Пароль
Запомнить меня