Удаление дескриптора из порта завершения ввода-вывода и другие вопросы о IOCP
на CreateIoCompletionPort
функция позволяет создать новый порт завершения ввода-вывода и регистрации дескрипторов файлов к существующему порту завершения ввода-вывода.
тогда я могу использовать любую функцию, например recv
на сокете или ReadFile
в файле с OVERLAPPED
структура для запуска асинхронной операции.
я должен проверить, вернулся ли вызов функции синхронно, хотя он был вызван с OVERLAPPED
структура и в этом случае справиться с этим непосредственно. В другом случае, когда ERROR_IO_PENDING
возвращается, я могу использовать GetQueuedCompletionStatus
функция, которая будет уведомлена, когда операция завершится.
вопрос, который возникает, являются:
как я могу удалить дескриптор из порта завершения ввода-вывода? Например, когда я добавляю сокеты в IOCP, как я могу удалить закрытые? Должен ли я просто перерегистрировать другой сокет с тем же ключом завершения?
кроме того, есть ли способ чтобы вызовы всегда проходили через порт завершения ввода-вывода и не возвращались синхронно?
и, наконец, возможно ли, например,
recv
асинхронно, ноsend
синхронно? Например, когда реализована простая служба echo: могу ли я ждать с асинхроннымrecv
для новых данных, ноsend
ответ синхронным образом, чтобы уменьшить сложность кода? В моем случае, я бы неrecv
второй раз в любом случае, прежде чем первый запрос был обработанный.что произойдет, если асинхронный
ReadFile
был запрошен, но прежде чем он завершится, aWriteFile
в тот же файл должен быть обработан. БудетReadFile
отменяется с сообщением об ошибке, и я должен перезапустить процесс чтения, как только запись завершена? Или мне нужно отменитьReadFile
вручную, прежде чем писать? Этот вопрос возникает в сочетании с устройством связи; таким образом, запись и чтение не должны делать проблемы, если происходит одновременно.
4 ответов
как я могу удалить дескриптор из порта завершения ввода-вывода?
по моему опыту, вы не можете отделить дескриптор от порта завершения. Однако вы можете отключить уведомление порта завершения, установив бит низкого порядка вашего OVERLAPPED
структуры hEvent
поле: см. документацию к GetQueuedCompletionStatus.
например, когда я добавляю сокеты в IOCP, как я могу удалить закрытые? Я Должен просто перерегистрируйте другой сокет с тем же ключом завершения?
нет необходимости явно отделять дескриптор от порта завершения ввода-вывода; достаточно закрыть дескриптор. Вы можете связать несколько дескрипторов с одним и тем же ключом завершения; лучший способ выяснить, какой запрос связан с завершением ввода-вывода, - использовать OVERLAPPED
структура. На самом деле, вы можете даже расширения OVERLAPPED
для хранения дополнительных данных.
кроме того, есть ли способ заставить вызовы всегда проходить через порт завершения ввода-вывода и не возвращаться синхронно?
это поведение по умолчанию, даже если ReadFile
/WriteFile
возвращает TRUE
. Вы должны явно вызвать SetFileCompletionNotificationModes указать Windows не поставит пакет завершения, когда TRUE
и ERROR_SUCCESS
возвращаются.
возможно ли, например,
recv
асинхронно, ноsend
синхронно?
не с помощью recv
и send
; вам нужно использовать функции, которые принимают OVERLAPPED
структуры, такие как WSARecv
, WSASend
или ReadFile
и WriteFile
. Было бы удобнее использовать последний, если ваш код предназначен для работы с несколькими типами дескрипторов ввода-вывода, такими как сокеты и именованные каналы. Эти функции обеспечивают синхронный режим, поэтому, если вы их используете, вы можете смешайте асинхронные и синхронные вызовы.
что произойдет, если был запрошен асинхронный файл чтения, но до его завершения должен быть обработан файл записи в тот же файл?
неявной отмены нет. Пока вы используете separate OVERLAPPED
структуры для каждого чтения / записи на полнодуплексное устройство, я не вижу причин, почему вы не можете выполнять параллельные операции ввода-вывода.
как я уже указал здесь, общепринятое мнение, что невозможно удалить дескрипторы из портов завершения, неверно, вероятно, вызвано отсутствием какого-либо намека на то, как это сделать почти из всей документации, которую я мог найти. На самом деле, это довольно просто:
вызов NtSetInformationFile
С FileReplaceCompletionInformation
значение перечислителя для FileInformationClass
и указатель на FILE_COMPLETION_INFORMATION
структура
во-первых, некоторые важные исправления.
в случае, если перекрывающаяся операция ввода-вывода завершается немедленно (ReadFile
или аналогичная функция ввода-вывода возвращает успех) - завершение ввода-вывода -уже запланировано к IOCP.
кроме того, в соответствии с вашими вопросами, я думаю, вы путаете между дескрипторами файлов/сокетов и конкретными операциями ввода-вывода, выданными на них.
теперь, что касается ваших вопросов:
- АФАИК нет обычный способ удалить дескриптор файла/сокета из IOCP (обычно вам просто не нужно этого делать). Вы говорите об удалении закрытые ручки из IOCP, что абсолютно неверно. Вы не можете удалить закрытый дескриптор, потому что он больше не ссылается на допустимый объект ядра!
более правильным вопросом должно быть то, как файл/сокет должен быть правильно закрыт. Ответ: просто закройте ручку. Все выдающие I / O операции (выданные на этом дескрипторе) скоро вернутся с кодом ошибки (аборт). Затем, в вашей процедуре завершения (тот, который вызывает GetQueuedCompletionStatus
в цикле) должен выполнить per-I / O необходимую очистку.
как я уже сказал, Все завершение ввода-вывода поступает в IOCP как в синхронном, так и в асинхронном случаях. Единственная ситуация, когда он не поступает в IOCP, - это когда ввод-вывод завершается синхронно с . В любом случае, если вы хотите Единой обработка-в таком случае вы можете опубликовать искусственные данные завершения в IOCP (используйте
PostQueuedCompletionStatus
).вы должны использовать
WSASend
иWSARecv
(неrecv
иsend
) для перекрытого ввода-вывода Тем не менее, даже сокет был открыт с флагомWSA_FLAG_OVERLAPPED
- вы разрешено для вызова функций ввода/вывода без указанияOVERLAPPED
структура. В таком случае эти функции работают синхронно. Так что вы можете принять решение о синхронных / асинхронных режимах для каждый вызов функции.нет проблем смешивать перекрывающиеся запросы на чтение/запись. Единственный деликатный момент здесь-это то, что происходит, если вы пытаетесь прочитать данные из позиции файла, в которую вы сейчас пишете. Результат может зависеть от тонких вещей, таких как порядок завершения ввода/вывода аппаратным обеспечением, некоторые параметры синхронизации ПК и т. д. Такой ситуации следует избегать.
как я могу удалить дескриптор из порта завершения ввода-вывода? Например, когда я добавляю сокеты в IOCP, как я могу удалить закрытые? Должен ли я просто перерегистрировать другой сокет с тем же ключом завершения?
вы неправильно поняли. Вы устанавливаете порт завершения ввода - вывода для использования файловым объектом-когда файловый объект удаляется, вам не о чем беспокоиться. Причина, по которой вы путаетесь, заключается в том, как Win32 предоставляет базовое собственные функции API (CreateIoCompletionPort
делает две очень разные вещи в одну функцию).
кроме того, есть ли способ сделать звонки Всегда переходите через порт завершения ввода-вывода и не возвращаются синхронно?
так было всегда. Только начиная с Windows Vista можно настроить способ обработки уведомлений о завершении.
что произойдет, если асинхронный ReadFile был запрошен, но до ее завершения, а WriteFile для такой же файл должен быть обработан. Будет ли ReadFile отменен с помощью сообщение об ошибке, и я должен перезагрузить процесс чтения, как только запись завершена?
операции ввода/вывода в Windows являются асинхронными по своей сути, и запросы всегда очереди. Вы можете не думать, что это так, потому что вы должны указать FILE_FLAG_OVERLAPPED
на CreateFile
чтобы включить асинхронный ввод-вывод. однако на собственном уровне синхронный ввод-вывод действительно является дополнением, удобством, где ядро отслеживает положение файла и ожидает завершения ввода-вывода перед возвращением.