Поделиться через


Синхронный и асинхронный ввод-вывод

См. также примеры приложений, связанных с вводом-выводом.

Синхронизация входных и выходных данных (ввода-вывода) существует два типа: синхронная синхронизация ввода-вывода и асинхронного ввода-вывода. Асинхронные ввода-вывода также называются перекрывающимися ввода-выводами.

В синхронном файле ввода-вывода поток запускает операцию ввода-вывода и немедленно вводит состояние ожидания до завершения запроса ввода-вывода. Поток, выполняющий асинхронный ввод-вывод файла, отправляет запрос ввода-вывода в ядро, вызывая соответствующую функцию. Если запрос принимается ядром, вызывающий поток продолжает обрабатывать другое задание, пока ядро не сигнализирует потоку о завершении операции ввода-вывода. Затем он прерывает текущее задание и обрабатывает данные из операции ввода-вывода по мере необходимости.

Два типа синхронизации показаны на следующем рисунке.

синхронные и асинхронные операции ввода-вывода

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

Вопросы синхронного и асинхронного ввода-вывода

Если файл или устройство открыто для синхронного ввода-вывода (то есть FILE_FLAG_OVERLAPPED не указано), последующие вызовы функций, таких как WriteFile, могут блокировать выполнение вызывающего потока до тех пор, пока не произойдет одно из следующих событий:

  • Операция ввода-вывода завершается (в этом примере запись данных).
  • Ошибка ввода-вывода. (Например, канал закрывается с другого конца.)
  • В самом вызове произошла ошибка (например, один или несколько параметров недопустимы).
  • Другой поток в процессе вызывает функцию CancelSynchronousIo , используя дескриптор потока заблокированного потока, который завершает операции ввода-вывода для этого потока, завершив операцию ввода-вывода.
  • Заблокированный поток завершается системой; Например, сам процесс завершается или другой поток вызывает функцию TerminateThread с помощью дескриптора заблокированного потока. (Как правило, это считается последним курортом и не хорошим дизайном приложений.)

В некоторых случаях эта задержка может быть неприемлемой для разработки и назначения приложения, поэтому конструкторы приложений должны рассмотреть возможность использования асинхронного ввода-вывода с соответствующими объектами синхронизации потоков, такими как порты завершения ввода-вывода. Дополнительные сведения о синхронизации потоков см. в разделе "О синхронизации".

Процесс открывает файл для асинхронного ввода-вывода в вызове CreateFile , указав флаг FILE_FLAG_OVERLAPPED в параметре dwFlagsAndAttributes . Если FILE_FLAG_OVERLAPPED не указан, файл открывается для синхронного ввода-вывода. Когда файл был открыт для асинхронного ввода-вывода, указатель на структуру OVERLAPPED передается в вызов ReadFile и WriteFile. При синхронном вводе-выводе эта структура не требуется в вызовах ReadFile и WriteFile.

Примечание.

Если файл или устройство открыто для асинхронного ввода-вывода, последующие вызовы функций, таких как WriteFile , с помощью этого дескриптора обычно возвращаются немедленно, но также могут вести себя синхронно в отношении заблокированного выполнения. Дополнительные сведения см. в разделе "Асинхронный ввод-вывод диска" как синхронный в Windows.

Хотя CreateFile — это наиболее распространенная функция для открытия файлов, томов дисков, анонимных каналов и других аналогичных устройств, операции ввода-вывода также можно выполнять с помощью дескриптора типа из других системных объектов, таких как сокет или прием функций.

Дескриптор объектов каталога получается путем вызова функции CreateFile с атрибутом FILE_FLAG_BACKUP_SEMANTICS. Дескрипторы каталогов почти никогда не используются. Приложения резервного копирования являются одним из немногих приложений, которые обычно используют их.

После открытия объекта файла для асинхронного ввода-вывода структура OVERLAPPED должна быть правильно создана, инициализирована и передана в каждый вызов функций, таких как ReadFile и WriteFile. Помните следующее при использовании структуры OVERLAPPED в асинхронных операциях чтения и записи:

  • Не отменяйте или не изменяйте структуру OVERLAPPED или буфер данных до завершения всех асинхронных операций ввода-вывода в объекте файла.
  • Если вы объявляете указатель на структуру OVERLAPPED как локальную переменную, не завершайте локальную функцию до завершения всех асинхронных операций ввода-вывода в объект файла. Если локальная функция завершается преждевременно, структура OVERLAPPED выходит из области, и она будет недоступна для любых функций ReadFile или WriteFile, которые она встречает вне этой функции.

Можно также создать событие и поместить дескриптор в структуру OVERLAPPED. Затем функции ожидания можно использовать для ожидания завершения операции ввода-вывода, ожидая обработки событий.

Как уже говорилось ранее, при работе с асинхронным дескриптором приложения должны использовать осторожность при определении того, когда следует освободить ресурсы, связанные с указанной операцией ввода-вывода в этом дескрипторе. Если дескриптор недопустим, ReadFile или WriteFile может неправильно сообщить о завершении операции ввода-вывода. Кроме того, функция WriteFile иногда возвращает ЗНАЧЕНИЕ TRUE со значением GetLastError ERROR_SUCCESS, даже если используется асинхронный дескриптор (который также может возвращать FALSE с ERROR_IO_PENDING). Программисты, привыкшие к синхронному проектированию операций ввода-вывода, обычно освобождают ресурсы буфера данных на этом этапе, так как значение TRUE и ERROR_SUCCESS означает, что операция завершена. Однако если порты завершения ввода-вывода используются с этим асинхронным дескриптором, пакет завершения также будет отправлен, даже если операция ввода-вывода завершена немедленно. Другими словами, если приложение освобождает ресурсы после возврата WriteFile значение TRUE с ERROR_SUCCESS в дополнение к подпрограмме порта завершения ввода-вывода, оно будет иметь состояние ошибки с двойной свободой. В этом примере рекомендуется разрешить подпрограмму порта завершения полностью отвечать за все операции освобождения таких ресурсов.

Система не поддерживает указатель на асинхронные дескрипторы файлов и устройств, поддерживающих указатели файлов (т. е. на поиске устройств), поэтому положение файла должно передаваться функциям чтения и записи в связанных элементах данных смещения структуры OVERLAPPED . Дополнительные сведения см. в разделе WriteFile и ReadFile.

Положение указателя файла для синхронного дескриптора поддерживается системой, так как данные считываются или записываются, а также можно обновлять с помощью функции SetFilePointer или SetFilePointerEx.

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

Чтобы отменить все ожидающие асинхронные операции ввода-вывода, используйте следующие действия:

  • CancelIo — эта функция отменяет только операции, выданные вызывающим потоком для указанного дескриптора файла.
  • CancelIoEx — эта функция отменяет все операции, выданные потоками для указанного дескриптора файла.

Используйте CancelSynchronousIo для отмены ожидающих синхронных операций ввода-вывода.

Функции ReadFileEx и WriteFileEx позволяют приложению указывать подпрограмму для выполнения (см. fileIOCompletionRoutine) при завершении асинхронного запроса ввода-вывода.