Порты завершения ввода-вывода (I/O) - это механизм при помощи которого, прикладная программа использует пул потоков, который создался, когда приложение запускалось, чтобы обработать запросы на асинхронный ввод/вывод (I/O) данных. Эти потоки создаются для единственной цели - обработки запросов на ввод-вывод данных. Прикладные программы, которые обрабатывают несколько параллельных запросов на асинхронный ввод/вывод (I/O) данных, могут сделать это более быстро и эффективно при помощи использования портов завершения ввода-вывода, чем при помощи использования создания потоков во время запроса на ввод-вывод (I/O) данных.
Функция CreateIoCompletionPort связывает порт завершения ввода-вывода с одними или несколькими дескрипторами файла. Когда начинается операция асинхронного ввода/вывода (I/O) данных, дескриптор файла, связанный с портом завершения, заканчивает работу, а пакет завершения ввода-вывода ставится в очередь порта. Это может быть использовано, чтобы объединять точку синхронизации для нескольких дескрипторов файла у отдельного объекта.
Поток использует функцию GetQueuedCompletionStatus, чтобы дождаться завершения работы пакета, который был поставлен в очередь порта завершения, а не ждать непосредственно асинхронного ввода/вывода (I/O) данных, чтобы закончить работу. Потоки, которые блокируют своё исполнение кода в порте завершения, освобождают ресурс в в обратном порядке - последним пришел, первым вышел (LIFO). Это означает то, что когда пакет завершения ставится в очередь порта завершения, система освобождает последний поток, чтобы блокировать его исполнение кода в порту.
Когда поток вызывает функцию GetQueuedCompletionStatus, он связывается с заданным портом завершения до тех пор, пока не выйдет из программы, указывает другой порт завершения или освобождает порт завершения. Поток может быть связан, самое большее, с одним портом завершения.
Самое важное свойство порта завершения - это значение параллелизма. Параметр параллелизма порта завершения определяется тогда, когда порт завершения создается. Это значение ограничивает число запускаемых потоков, связанных с портом завершения. Когда общее количество запускаемых потоков, связанных с портом завершения, достигает значения параллелизма, система блокирует исполнение кода любых последующих потоков, которые указывают порт завершения до тех пор, пока число запускаемых потоков, связанных с портом завершения не упадет ниже значения параллелизма. Самый эффективный сценарий происходит тогда, когда имеемые пакеты завершения ожидают своей очереди, но ожидание может быть не удовлетворено, потому что порт достиг своего граничного предела параллелизма. В этом случае, когда запущенный поток вызывает GetQueuedCompletionStatus, он немедленно извлекает пакет завершения из очереди. Не произойдет никаких переключений контекста, потому что запущенный поток все время забирает пакеты завершения, а другие потоки неспособны запуститься.
Лучшим значением для выбора значения параллелизма является число центральных процессоров на компьютере. Если Ваша транзакция потребовала длительного вычисления, большее значение параллелизма даст возможность запуститься большему количеству потоков. Каждая транзакция займет больше времени для завершения работы, но зато больше транзакций будет обработано в то же самое время. Легко экспериментировать со значением параллелизма, чтобы достигнуть лучшего результата для Вашего приложения.
Функция PostQueuedCompletionStatus дает возможность приложению ставить в очередь свои собственные пакеты завершения ввода-вывода специального назначения в порту завершения, не начиная операцию асинхронного ввода/вывода (I/O) данных. Это полезно для уведомления рабочих потоков внешних событий.
Порт завершения освобождается тогда, когда нет больше ссылок на него. Дескриптор порта завершения и каждый дескриптор файла, связанный с портом завершения, ссылаются на порт завершения. Все дескрипторы должны закрыться, чтобы освободить порт завершения. Чтобы закрыть дескриптор порта, вызовите функцию CloseHandle.