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

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

В случае если было инициировано слишком большое количество запросов на асинхронный ввод/вывод, функция ReadFile может завершиться возвратом значения ERROR_INVALID_USER_BUFFER или ERROR_NOTENOUGH_MEMORY. Лично я с этим не сталкивался, однако рекомендую вам всегда завершать инициированные вами запросы на выполнение ввода/вывода так быстро, как это возможно.

Использование событий

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

Создайте событие так, как мы делали это в лаб.работе по синхронизации потоков. Занесите дескриптор этого события в одно из полей структуры OVERLAPPED. При обращении к функциям ввода/вывода (ReadFile или WriteFile) передайте в качестве одного из аргументов указатель на эту структуру. Если операцию ввода/вывода нельзя выполнить немедленно, система сбросит событие. Как только операция ввода/вывода будет завершена, система переведет событие в сигнальное состояние.

Неужели такой метод лучше? В определенных ситуациях — да. Представьте, что вы разрабатываете программу чтения данных из двух последовательных портов. Когда вы обнаруживаете данные, ожидающие чтения в одном из портов, вы передаете эти данные в другой порт. Если данные поступают к вам через второй порт, вы передаете их в первый порт. Такое приложение может выполнять функции мониторинга потока данных.

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

Использование вызовов ReadFileEx и WriteFileEx

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