Составители:
Однако для того, чтобы произошло обращение к функции завершения, поток, обра-
тившийся к ReadFileEx() или WriteFileEx(), должен находиться в «настороженном» со-
стоянии. Чтобы перейти в настороженное состояние, необходимо использовать вызовы
WaitForSingleObject() или SleepEx(). Находясь в настороженном состоянии, поток не вы-
полняет никаких действий, а просто ждет, когда в результате завершения операции вво-
да/вывода произойдет обращение к функции завершения.
Все эти особенности перекрывающегося ввода/вывода несколько обескураживают.
Перекрывающийся ввод/вывод удобен во многих ситуациях, однако он не настолько
асинхронный, как этого хотелось бы программистам. Чтобы реализовать действительно
асинхронный ввод/вывод, следует создать отдельный программный поток, в рамках ко-
торого использовать обычные функции ввода/вывода. В качестве альтернативы при раз-
работке некоторых программ можно использовать порты завершения ввода/вывода (о
них речь пойдет чуть позже).
Если традиционная функция чтения данных в процессе осуществления операции
ввода встречает символ EOF, она тем или иным образом оповещает об этом вызываю-
щую программу. В частности, традиционный вызов ReadFile() устанавливает количество
прочитанных байт равным нулю. Если символ EOF встречается в процессе выполнения
перекрывающегося вызова ReadFile(), вызов возвращает ошибку. В этом случае значе-
ние, возвращаемое функцией GetLastError(), будет равно ERROR_HANDLE_EOF. Сим-
вол EOF может встретиться непосредственно при обращении к функции ReadFile() или
позже, в процессе выполнения операции ввода/вывода.
Порты завершения ввода/вывода. Перекрывающийся ввод/вывод обладает массой
ограничений. Фактически при использовании перекрывающегося ввода/вывода для об-
мена данными с некоторым объектом (файлом или устройством) используется отдель-
ный программный поток. Например, если вы планируете использовать перекрывающий-
ся ввод/вывод при разработке сетевого сервера, обслуживанием каждого из клиентов
будет заниматься отдельный программный поток. Такая схема будет отлично работать в
случае, если число клиентов небольшое. Однако вряд ли удастся использовать подобный
подход для обеспечения работы высокопроизводительного сервера, обслуживающего
одновременно достаточно большое количество клиентов. Не всякий компьютер сможет
обеспечить создание и поддержку работы нескольких тысяч программных потоков од-
новременно. Может ли один поток обслуживать одновременно нескольких клиентов?
Этого можно достичь, если использовать порты завершения ввода/вывода (I/O comple-
tion ports) [1].
Порт завершения ввода/вывода напоминает очередь. В эту очередь заносятся уве-
домления о том, что та или иная процедура ввода/вывода завершена. Любой поток мо-
жет проверить очередь и отреагировать на любое из этих уведомлений. Прежде чем
можно будет приступить к использованию порта завершения ввода/ вывода, необходимо
создать его при помощи вызова CreateIoCompletionPort().
HANDLE CreateIoCompletionPort (HANDLE FileHandle, // дескриптор файла
HANDLE ExistingCompletionPort, // дескриптор создаваемого
// (или открываемого) порта завершения
ULONG_PTR CompletionKey, // ключ завершения,
// вставляемый в каждый пакет
DWORD NumberOfConcurrentThreads ); //количество подключаемых
// потоков
В качестве одного из аргументов эта функция принимает дескриптор файла, от-
крытого для перекрывающегося ввода/вывода. Как только дескриптору файла ставится в
соответствие порт завершения ввода/вывода, при успешном завершении любой опера-
140
Однако для того, чтобы произошло обращение к функции завершения, поток, обра-
тившийся к ReadFileEx() или WriteFileEx(), должен находиться в «настороженном» со-
стоянии. Чтобы перейти в настороженное состояние, необходимо использовать вызовы
WaitForSingleObject() или SleepEx(). Находясь в настороженном состоянии, поток не вы-
полняет никаких действий, а просто ждет, когда в результате завершения операции вво-
да/вывода произойдет обращение к функции завершения.
Все эти особенности перекрывающегося ввода/вывода несколько обескураживают.
Перекрывающийся ввод/вывод удобен во многих ситуациях, однако он не настолько
асинхронный, как этого хотелось бы программистам. Чтобы реализовать действительно
асинхронный ввод/вывод, следует создать отдельный программный поток, в рамках ко-
торого использовать обычные функции ввода/вывода. В качестве альтернативы при раз-
работке некоторых программ можно использовать порты завершения ввода/вывода (о
них речь пойдет чуть позже).
Если традиционная функция чтения данных в процессе осуществления операции
ввода встречает символ EOF, она тем или иным образом оповещает об этом вызываю-
щую программу. В частности, традиционный вызов ReadFile() устанавливает количество
прочитанных байт равным нулю. Если символ EOF встречается в процессе выполнения
перекрывающегося вызова ReadFile(), вызов возвращает ошибку. В этом случае значе-
ние, возвращаемое функцией GetLastError(), будет равно ERROR_HANDLE_EOF. Сим-
вол EOF может встретиться непосредственно при обращении к функции ReadFile() или
позже, в процессе выполнения операции ввода/вывода.
Порты завершения ввода/вывода. Перекрывающийся ввод/вывод обладает массой
ограничений. Фактически при использовании перекрывающегося ввода/вывода для об-
мена данными с некоторым объектом (файлом или устройством) используется отдель-
ный программный поток. Например, если вы планируете использовать перекрывающий-
ся ввод/вывод при разработке сетевого сервера, обслуживанием каждого из клиентов
будет заниматься отдельный программный поток. Такая схема будет отлично работать в
случае, если число клиентов небольшое. Однако вряд ли удастся использовать подобный
подход для обеспечения работы высокопроизводительного сервера, обслуживающего
одновременно достаточно большое количество клиентов. Не всякий компьютер сможет
обеспечить создание и поддержку работы нескольких тысяч программных потоков од-
новременно. Может ли один поток обслуживать одновременно нескольких клиентов?
Этого можно достичь, если использовать порты завершения ввода/вывода (I/O comple-
tion ports) [1].
Порт завершения ввода/вывода напоминает очередь. В эту очередь заносятся уве-
домления о том, что та или иная процедура ввода/вывода завершена. Любой поток мо-
жет проверить очередь и отреагировать на любое из этих уведомлений. Прежде чем
можно будет приступить к использованию порта завершения ввода/ вывода, необходимо
создать его при помощи вызова CreateIoCompletionPort().
HANDLE CreateIoCompletionPort (HANDLE FileHandle, // дескриптор файла
HANDLE ExistingCompletionPort, // дескриптор создаваемого
// (или открываемого) порта завершения
ULONG_PTR CompletionKey, // ключ завершения,
// вставляемый в каждый пакет
DWORD NumberOfConcurrentThreads ); //количество подключаемых
// потоков
В качестве одного из аргументов эта функция принимает дескриптор файла, от-
крытого для перекрывающегося ввода/вывода. Как только дескриптору файла ставится в
соответствие порт завершения ввода/вывода, при успешном завершении любой опера-
140
Страницы
- « первая
- ‹ предыдущая
- …
- 136
- 137
- 138
- 139
- 140
- …
- следующая ›
- последняя »
