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

Выполняя перекрывающийся ввод/вывод при помощи функций ReadFile и WriteFile, в качестве одного из аргументов вы передаете этим функциям указатель на структуру OVERLAPPED. Первые два 32-битных слова этой структуры зарезервированы системой для внутреннего использования. Вторые два слова могут содержать 64-битное смещение, указывающее на позицию файла, в которой будет осуществляться чтение или запись данных. Ввод/вывод осуществляется асинхронно, поэтому не существует гарантий, что данные из файла будут извлекаться (или записываться) последовательно байт за байтом. Таким образом, при выполнении перекрывающегося ввода/вывода не существует понятия текущей позиции. При выполнении любой операции вы просто указываете смещение в файле. Если вы работаете с потоками данных (например, последовательный порт или сокет), понятие смещения теряет смысл, поэтому система игнорирует соответствующее поле структуры OVERLAPPED.

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

Когда происходит обращение к функции асинхронного ввода/вывода, система может завершить процедуру ввода/вывода немедленно. Например, вы можете приказать системе выполнить чтение одного байта из последовательного устройства и записать этот байт в 30-байтный буфер, ожидающий ввода. В этом случае функция ввода/вывода завершает свою работу так, словно вы и не использовали при этом механизмов перекрывающегося ввода/вывода. Запомните: если функция вернула ненулевое значение, значит, операция ввода/вывода успешно завершена, а передача данных произошла фактически точно так же, как если бы вы не использовали перекрывающегося ввода/вывода.

Особенности асинхронного ввода/вывода проявляются в случае, если функция возвращает значение FALSE. Нулевое значение, возвращенное функцией ввода/вывода, означает, что либо процедура ввода/вывода находится в стадии выполнения, либо произошла какая-либо ошибка. Чтобы уточнить, чем, собственно, завершился вызов функции, необходимо вызвать функцию GetLastError. Если этот вызов вернул значение ERROR_IO_PENDING, значит, запрос на ввод/вывод либо ожидает своей очереди, либо находится в стадии выполнения. Любое другое значение означает, что произошла ошибка.

Завершение ввода/вывода

Если вы обратились к функции ввода/вывода и получили подтверждение того, что запрос на ввод/вывод находится в процессе исполнения, рано или поздно вы захотите узнать, когда же все-таки осуществление ввода/вывода завершится? Если вы осуществляете чтение данных, вы не сможете использовать данные из буфера чтения до того момента, пока не завершится операция чтения. Если вы осуществляете запись, рано или поздно вы должны убедиться в том, что процедура записи успешно завершена.

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

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