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


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

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

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

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

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

Соображения по поводу синхронного и асинхронного ввода-вывода

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

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

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

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

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

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

После открытия объекта file для асинхронного ввода-вывода перекрывающаяся структура должна быть правильно создана, инициализирована и передана в каждый вызов таких функций, как ReadFile и WriteFile. При использовании ПЕРЕКРЫВАЮЩЕЙСЯ структуры в асинхронных операциях чтения и записи имейте в виду следующее:

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

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

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

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

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

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

Поэтому, если приложение запускает две операции ввода-вывода и ожидает дескриптор файла, нет никакого способа определить, какая операция завершена, когда дескриптор установлен в сигнальное состояние. Если приложение должно выполнить несколько асинхронных операций ввода-вывода в одном файле, оно должно ожидать дескриптора события в определенной ПЕРЕКРЫВАЮЩЕЙСЯ структуре для каждой операции ввода-вывода, а не общего дескриптора файла.

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

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

Функции ReadFileEx и WriteFileEx позволяют приложению указать процедуру для выполнения (FileIOCompletionRoutine) после завершения асинхронного запроса ввода-вывода.
Автор этого материала - я - Пахолков Юрий. Я оказываю услуги по написанию программ на языках Java, C++, C# (а также консультирую по ним) и созданию сайтов. Работаю с сайтами на CMS OpenCart, WordPress, ModX и самописными. Кроме этого, работаю напрямую с JavaScript, PHP, CSS, HTML - то есть могу доработать ваш сайт или помочь с веб-программированием. Пишите сюда.



тегистатьи IT, windows, файл, файловая система




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



Прозрачность пикселя на Java
Рецензия на книгу Кристофер Мур Грязная работа
Ошибки соединения с базой данных Laravel, или чудес не бывает