Синхронизация и перекрывающиеся входные и выходные данные

Вы можете выполнять синхронные или асинхронные (также называемые перекрывающимися) операции ввода-вывода для файлов, именованных каналов и устройств последовательной связи. Функции WriteFile, ReadFile, DeviceIoControl, WaitCommEvent, ConnectNamedPipe и TransactNamedPipe можно выполнять синхронно или асинхронно. Функции ReadFileEx и WriteFileEx можно выполнять только асинхронно.

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

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

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

Для перекрывающихся операций требуется файл, именованный канал или устройство связи, созданное с флагом FILE_FLAG_OVERLAPPED . Когда поток вызывает функцию (например, функцию ReadFile ) для выполнения перекрывающейся операции, вызывающий поток должен указать указатель на структуру OVERLAPPED . (Если этот указатель имеет значение NULL, возвращаемое значение функции может неправильно указывать на то, что операция завершена.) Все члены структуры OVERLAPPED должны быть инициализированы до нуля, если событие не будет использоваться для обозначения завершения операции ввода-вывода. Если используется событие, элемент hEvent структуры OVERLAPPED задает дескриптор выделенного объекта события. Система устанавливает состояние объекта события без знака, когда вызов функции ввода-вывода возвращается до завершения операции. Система задает состояние объекта события на сигнал, когда операция была завершена. Событие требуется только в том случае, если одновременно будет несколько невыполненных операций ввода-вывода. Если событие не используется, каждая завершенная операция ввода-вывода будет сигнализировать о файле, именованном канале или устройстве связи.

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

Поток может управлять перекрывающимися операциями с помощью двух методов:

  • Используйте функцию GetOverlappedResult или GetOverlappedResultEx , чтобы дождаться завершения перекрывающейся операции. Если используется getOverlappedResultEx , вызывающий поток может указать время ожидания для перекрывающейся операции или выполнить ожидание с оповещениями.
  • Укажите дескриптор для объекта события ручного сброса структуры OVERLAPPED в одной из функций ожидания , а затем, после возврата функции ожидания, вызовите Метод GetOverlappedResult или GetOverlappedResultEx. Функция возвращает результаты завершенной перекрывающейся операции, а для функций, в которых такая информация подходит, сообщает фактическое количество переданных байтов.

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

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

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

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

Windows Vista, Windows Server 2003 и Windows XP:

Будьте осторожны при повторном использовании перекрывающихся структур. Если структуры OVERLAPPED повторно используются в нескольких потоках и метод GetOverlappedResult вызывается с параметром bWait, для параметра bWaitзадано значение TRUE, вызывающий поток должен убедиться, что связанное событие будет показано перед повторным использованием структуры. Это можно сделать с помощью функции WaitForSingleObject после вызова Метода GetOverlappedResult , чтобы заставить поток ждать завершения операции. Обратите внимание, что объект события должен быть объектом события сброса вручную. Если используется объект события автовосстановки, вызов GetOverlappedResult с параметром bWait , равным TRUE , приводит к блокировке функции на неопределенный срок. Это поведение изменилось начиная с Windows 7 и Windows Server 2008 R2 для приложений, которые указывают Windows 7 в качестве поддерживаемой операционной системы в манифесте приложения. Дополнительные сведения см. в разделе Манифесты приложений.

Основные понятия ввода-вывода