Возможно ли принудительно завершить операцию асинхронного чтения, инициированную FileStream.BeginRead, без ошибок? - PullRequest
0 голосов
/ 29 августа 2011

Прежде всего, документация для EndRead NOT явно говорит о том, что асинхронная операция чтения, инициированная BeginRead, является атомарной или непрерывной.

Вопрос

Можно ли прервать операцию асинхронного чтения, начатую FileStream.BeginRead, чтобы она заканчивалась до заполнения буфера, возвращая количество байтов, считанных в буфер на данный момент, или это операция "все или ничего"?

Другими словами, есть ли такой метод, как «Cancel_IO», который я могу вызвать, чтобы при вызове EndRead вместо ожидания считывания всех возможных байтов он возвращался раньше в результате отмены чтения

Фон

Я прочитал документацию по FileStream, BeginRead и EndRead. EndRead не имеет никаких перегрузок, способных вызвать преждевременное завершение операции, возвращая частично полный буфер. Меня интересует, может ли кто-нибудь подтвердить или опровергнуть существование метода в API операционной системы Windows (Win32) или, возможно, API-интерфейса драйвера диска, который может привести к преждевременному завершению операции, инициированной FileStream.BeginRead, когда EndRead называется. Под «ранним» я подразумеваю перед заполнением всю запрашиваемую длину буфера без ошибки.

Вариант использования

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

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

О документации

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

Например, «конец файла» и «заполнение буфера» могут рассматриваться как два «естественных» прерывания асинхронной операции чтения, которые приводят к тому, что она возвращает без количества запрошенных байтов без ошибок. Я ищу "искусственные" возможности прерывания, которые также заставили бы EndRead успешно возвращать число байтов, считанных в буфер, до EOF и до того, как буфер заполнен.

Ответы [ 3 ]

2 голосов
/ 29 августа 2011

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

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

0 голосов
/ 02 сентября 2011

Нет; нет API, который может это сделать.

Закрытие дескриптора - старый трюк - он работает еще во времена NT. Однако это приводит к тому, что все незавершенные операции над дескриптором завершаются с ошибкой.

Отмена имеет похожие проблемы - и учтите, что CancelIoEx может быть недоступно на вашей платформе.

SetCommTimeouts не вариант, поскольку он работает только на последовательных портах и ​​других дескрипторах устройств связи.

Отмена исторически была одной из самых сложных частей написания драйвера устройства. В настоящее время ядро ​​имеет встроенную в XP поддержку Cancel-Safe Queue (с возможностью переноса до 2K), и это намного проще. Но многие водители (особенно старшие) в любом случае просто игнорируют отмену (что законно).

Я рекомендую реализовать «отмену» на более высоком уровне абстракции: закройте дескриптор или дождитесь завершения операции и проигнорируйте результат.

0 голосов
/ 29 августа 2011

Я прочитал кое-что в документации для синхронного и асинхронного ввода-вывода Windows , что может помочь, но это будет с неопределенными последствиями.

"Еслидескриптор освобождается преждевременно, ReadFile или WriteFile могут некорректно сообщать о завершении операции ввода-вывода. "

Поскольку метод .NET BeginRead в конечном счете основан на методе Win32 ReadFile, то получение и преждевременное получениеосвобождение ручки может выполнить то, что я пытаюсь сделать.Последствия этого требуют изучения.

В нем также упоминается «Чтобы отменить все ожидающие операции асинхронного ввода-вывода, используйте: CancelIo или CancelIoEx », но этипоявляется, чтобы отменить все операции с ошибкой (ERROR_OPERATION_ABORTED).Я не уверен, были ли какие-либо прочитанные байты уже записаны в буфер, и даже если бы они были, никто бы не знал, сколько было успешно записано.Интересно, есть ли способ заставить основную систему думать, что она внезапно достигла конца файла или потока ...

Я также вижу, что метод " SetCommTimeouts " имеет некоторыеинтересные результаты, в частности, вокруг элемента " COMMTIMEOUTS""ReadIntervalTimeout", который утверждает, что:

"Если интервал между прибытием любых двух байтов превышает этотсумма, операция ReadFile завершена, и любые буферизованные данные возвращены. "

Это кажется многообещающим ...

В любом случае, тот факт, что я могу отменить ожидающий асинхронный I/ O полезно.Я мог бы на самом деле вычислить, используя статистику буферизации и время запуска, стоило ли бы отменить асинхронное чтение и переиздать меньшее чтение желаемого фрагмента данных или лучше подождать завершения операции.Это будет зависеть от рассчитанной средней скорости потока, а также от того, насколько он близок к завершению (на основе его вычисленного / прогнозируемого значения прогресса) и ожидаемого времени завершения, взвешенного по отношению к относительной полезности получения желаемого фрагмента данных.

...