Асинхронный файловый ввод/вывод в операционной системе WINDOWS, страница 19

Последнее поле структуры OVERLAPPED может быть равно нулю, однако, если его значение отлично от нуля, система интерпретирует его как дескриптор события. О том, как используется это событие, рассказывается в следующем подразделе.

Возможно, в момент, когда вы инициируете операцию асинхронного чтения или записи, данные для ввода/вывода уже доступны для вашей программы. Такая ситуация может возникнуть в случае, если данные находятся в кэше или устройство (или сокет) уже готово к вводу/выводу данных.

В подобной ситуации вызов возвращает значение TRUE. Это значит, что выполнение вызова завершилось успехом. Такая операция фактически ничем не отличается от обычного ввода/вывода. Однако в случае, если операция ввода/ вывода не выполнена, вызов возвращает значение FALSE. Если вы используете обычный ввод/вывод, значит, операция завершилась неудачей. Однако при использовании перекрывающегося ввода/вывода в этом случае необходимо проверить значение, возвращаемое вызовом GetLastError. Если этот вызов возвращает значение ERROR_IO_ PENDING, значит, никакой ошибки на самом деле не произошло. Просто на момент завершения работы вызова ReadFile или WriteFile операция ввода/вывода еще не завершилась и находится в стадии выполнения.

В этом случае необходимо осуществить проверку на завершение операции чуть позже. Об этом будет рассказано в следующем подразделе.

Завершение операции перекрывающегося ввода/вывода

Если вызов ReadFile или WriteFile возвращает ненулевое значение, значит, процедура ввода/вывода завершилась без промедления. Если же вызов вернул значение FALSE, а функция GetLastError возвращает значение ERROR_IO_PENDING, значит, завершения операции ввода/вывода следует подождать, Отменить операцию ввода/вывода можно при помощи вызова CanselIo. При этом выполнение операции будет прервано (чаще всего это не то, что вам нужно).

Подождать завершения операции ввода/вывода можно при помощи вызова GetOverlappedResult, Вы можете приказать этой функции ждать завершения операции неограниченное время. В этом случае функция завершит свое выполнение и вернет управление вызвавшей программе либо в момент завершения операции ввода/вывода, либо при возникновении ошибки ввода/вывода. Время ожидания можно ограничить. Наконец, функция GetOverlappedResult может вообще не ждать (время ожидания равно нулю). Если в последних двух случаях функция вернет значение FALSE, необходимо обратиться к вызову GetLastError. Если ввод/вывод все еще не завершен, вызов вернет значение ERROR_IO_INCOMPLETE. Это означает, что операция ввода/вывода все еще находится в стадии выполнения.

Узнать о завершении операции перекрывающегося ввода/вывода можно также при помощи события, дескриптор которого записывается в одно из полей структуры OVERLAPPED. Событие продолжает оставаться не установленным до тех пор, пока операция ввода/вывода находится в стадии выполнения. Как только ввод/ вывод завершается, событие переходит в сигнальное состояние. Используя несколько таких событий, можно организовать ожидание завершения сразу нескольких операций ввода/вывода (см. листинг 2).

Помимо указанных в данном разделе существуют также другие способы следить за завершением операций перекрывающегося ввода/вывода. В частности, для этой цели можно использовать функции ReadEx и WriteEx, а также порты завершения. Об этих методах речь пойдет далее.

Определение EOF при асинхронном вводе/выводе

При асинхронном (или перекрывающемся) вводе/выводе определить конец файла несколько сложнее, чем при синхронном вводе/выводе. Дело в том, что при обращении к функции ReadFile система только инициирует операцию чтения данных, но не обязательно завершает ее. Так как в момент завершения функции ReadFile операция чтения данных может все еще находиться в стадии выполнения, система не может сообщить вызывающей программе, будет ли в ходе операции обнаружен конец файла.