Может ли запуск нескольких асинхронных операций чтения / записи в одном потоке повредить данные?

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

Предположим, я хочу отправить 3 буфера:

Buffer1: 1111111111
Buffer2: 2222222222
Buffer3: 3333333333

Я не против, если буферы будут отправлены в неправильном порядке, поэтому

333333333311111111112222222222

это нормально, но возможно ли, что содержимое буфера полностью перемешано?

122213121212122333313111223333

PS: Я на 100% уверен, что кто-то уже спрашивал об этом в какой-то форме ...


person Calmarius    schedule 20.05.2011    source источник
comment
Не имеет значения, в каком порядке отправляются 3 буфера? Что делать, если данные отправляются как 222233331111, т.е. нет чередования, но неправильный порядок?   -  person Lasse V. Karlsen    schedule 21.05.2011
comment
Да, аналогичный вопрос: stackoverflow.com/questions/1540658/   -  person MPelletier    schedule 21.05.2011
comment
Думаю, тебе не стоит этого делать. MSND сообщает об объекте Stream - безопасность потоков не гарантируется для любых членов экземпляра.   -  person Maxim    schedule 21.05.2011
comment
Обязательно прочтите support.microsoft.com/default.aspx? scid = kb; en-us; 156932, особенно та часть, которая говорит: «Другая причина того, что операции ввода-вывода выполняются синхронно, - это сами операции. В Windows NT любая операция записи в файл, увеличивающая его длину, будет синхронной.   -  person Jim Mischel    schedule 21.05.2011


Ответы (2)


Это зависит от реализации Stream. Например, сокеты поддерживают несколько перекрывающихся запросов как на чтение, так и на запись, как и файловый API. Они гарантируют согласованность каждой операции (без чередования содержимого), а также порядок операций: например, для чтения сокетов полученные байты будут помещены в отправленные буферы в указанном порядке. Если бы эти гарантии не были предоставлены, было бы невозможно написать высокопроизводительное сетевое приложение, поскольку перекрывающиеся отправки желательны, а перекрывающиеся получения фактически требуются для высокопроизводительного сетевого ввода-вывода. Это поведение описано во многих статьях, в том числе в хорошей старой 'Windows Sockets 2.0: написание масштабируемых приложений Winsock с использованием портов завершения и задокументирован в MSDN перекрывающийся ввод / вывод :

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

Неудивительно, что те же гарантии распространяются и на управляемую сторону мира, например. класс NetworkStream:

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

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

И последнее замечание: все эти асинхронные API делают специальное примечание, указывая, что порядок завершения не обязательно соответствует порядку отправки.

person Remus Rusanu    schedule 20.05.2011
comment
Так что в основном, если я заблокирую NetworkStream при вызове BeginWrite, у меня не будет проблем, и одновременное выполнение асинхронных операций не будет конфликтовать друг с другом. - person Calmarius; 21.05.2011

Нет, файловые потоки не поддерживают несколько одновременных операций ввода-вывода. Файловая система Windows не справляется с этим. Это почти наверняка вызовет исключение.

Редактировать:

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

Однако не пытайтесь выполнять одновременную синхронную запись на FileStream. Это вызывает исключение.

person Jim Mischel    schedule 20.05.2011
comment
-1 На MSDN есть обширная документация, доказывающая обратное. - person Remus Rusanu; 21.05.2011
comment
@Remus: дайте ссылку. - person Jim Mischel; 21.05.2011
comment
В моем ответе есть несколько ссылок - person Remus Rusanu; 21.05.2011
comment
@Remus: Все они упоминают сокеты Windows, а не файловый API. Я пойду посмотрю. - person Jim Mischel; 21.05.2011