Синхронный и перекрываемый канал ввода-вывода
ReadFile, WriteFile, TransactNamedPipe, а Функции ConnectNamedPipe могут выполнять операции ввода и вывода в канале синхронно или асинхронно. Когда функция выполняется синхронно, она не возвращается до завершения операции. Это означает, что выполнение вызывающего потока может быть заблокировано в течение неопределенного периода, пока оно ожидает завершения операции. Когда функция выполняется асинхронно, она возвращается немедленно, даже если операция не завершена. Это позволяет выполнять в фоновом режиме много времени, пока вызывающий поток не может выполнять другие задачи.
Использование асинхронного ввода-вывода позволяет серверу канала использовать цикл, выполняющий следующие действия:
- Укажите несколько объектов событий в вызове функции ожидания и подождите, пока один из объектов будет задан в сигнальном состоянии.
- Используйте возвращаемое значение функции ожидания, чтобы определить, какая перекрывающаяся операция завершена.
- Выполните задачи, необходимые для очистки завершенной операции, и инициируйте следующую операцию для этого дескриптора канала. Это может включать запуск другой перекрывающейся операции для того же дескриптора канала.
Перекрывающиеся операции позволяют одному каналу одновременно считывать и записывать данные, а для одного потока выполнять одновременные операции ввода-вывода на нескольких дескрипторах каналов. Это позволяет однопоточному серверу каналов эффективно обрабатывать обмен данными с несколькими клиентами каналов. Пример см. в разделе Именованный сервер канала с использованием перекрывающихся операций ввода-вывода.
Чтобы сервер канала использовал синхронные операции для взаимодействия с несколькими клиентами, он должен создать отдельный поток для каждого клиента канала, чтобы один или несколько потоков могли выполняться в ожидании других потоков. Пример многопоточного сервера канала, использующего синхронные операции, см. в разделе многопоточный сервер канала.
Включение асинхронной операции
ReadFile, WriteFile, TransactNamedPipeи функции ConnectNamedPipeConnectNamedPipe можно выполнять асинхронно, только если включить перекрывающийся режим для указанного дескриптора каналаи указать допустимый указатель на структуру OVERLAPPED. Если указатель OVERLAPPED NULL, возвращаемое значение функции может неправильно указать, что операция завершена. Поэтому настоятельно рекомендуется, чтобы при создании дескриптора с FILE_FLAG_OVERLAPPED и требуется асинхронное поведение, всегда следует указать допустимую структуру OVERLAPPED.
Элемент hEvent указанной структуры OVERLAPPED должен содержать дескриптор объекта события сброса вручную. Это объект синхронизации, созданный функцией CreateEvent. Поток, инициирующий перекрываемую операцию, использует объект события для определения завершения операции. Не следует использовать дескриптор канала для синхронизации при выполнении одновременных операций с тем же дескриптором, так как невозможно знать, какое завершение операции привело к сигнализации дескриптора канала. Единственный надежный способ выполнения одновременных операций с тем же дескриптором канала — использовать отдельную структуру OVERLAPPED со своим собственным объектом события для каждой операции. Дополнительные сведения о объектах событий см. в синхронизации.
Кроме того, вы можете получать уведомления о завершении перекрывающейся операции с помощью функций GetQueuedCompletionStatus или GetQueuedCompletionStatusEx. В этом случае не нужно назначать событие ручного сброса в структуре OVERLAPPED, а завершение выполняется с дескриптором канала так же, как асинхронная операция чтения или записи. Дополнительные сведения см. в портах завершения ввода-вывода.
Когда ReadFile, WriteFile, TransactNamedPipeи ConnectNamedPipe выполняются асинхронно, одно из следующих действий:
- Если операция завершается, когда функция возвращается, возвращаемое значение указывает на успешность или сбой операции. Если возникает ошибка, возвращаемое значение равно нулю, а функция GetLastError возвращает значение, отличное от ERROR_IO_PENDING.
- Если операция не завершена, когда функция возвращается, возвращаемое значение равно нулю, и GetLastError возвращает ERROR_IO_PENDING. В этом случае вызывающий поток должен ждать завершения операции. Затем вызывающий поток должен вызвать функцию getOverlappedResult, чтобы определить результаты.
Использование подпрограмм завершения
Функции ReadFileEx и WriteFileEx предоставляют другую форму перекрывающихся операций ввода-вывода. В отличие от перекрывающихся функций ReadFile и функций WriteFile, которые используют объект события для сигнала о завершении, расширенные функции указывают подпрограмму завершения. Подпрограмма завершения — это функция, которая помещается в очередь для выполнения после завершения операции чтения или записи. Подпрограмма завершения не выполняется до тех пор, пока поток, который вызывает ReadFileEx и WriteFileEx запускает операции ожидания, вызвав одну из оповещенных функций ожидания с параметром fAlertable значение TRUE. В операции ожидания с оповещением функции также возвращаются, когда подпрограмма завершения ReadFileEx или WriteFileEx выполняется в очередь. Сервер канала может использовать расширенные функции для выполнения последовательности операций чтения и записи для каждого клиента, который подключается к нему. Каждая операция чтения или записи в последовательности задает подпрограмму завершения, и каждая подпрограмма завершения инициирует следующий шаг в последовательности. Пример см. в разделе Именованный сервер конвейера с помощью подпрограмм завершения.