Как бороться с позицией в aC# stream

(Вся) документация для position Свойство в потоке говорит:

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

Вот и все. Хорошо, так что мы достаточно ясно понимаем, о чем это нам не говорит, но мне бы очень хотелось узнать, что это на самом деле означает. Для чего нужна позиция? Почему мы хотим изменить или прочитать это? Если мы изменим это - что произойдет?

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

  • Влияет ли это на то, где средство записи в этот поток попытается поместить данные? Нужно ли отслеживать последнюю позицию записи самостоятельно? (т.е. если я установлю позицию в ноль для чтения, писатель начнет перезаписывать все с первого байта?)
  • Если так, нужен ли мне семафор / блокировка вокруг этого поля 'position' (возможно, подкласса?) Из-за того, что мои два потока обращаются к нему?
  • Если я не обработаю это свойство, писатель просто переполнит буфер?

Возможно, я не понимаю сам поток - я рассматриваю его как канал FIFO: засунуть данные с одного конца, а отсосать с другого. Если этоне так, то нужно ли мне продолжать копировать данные после моего последнего чтения (т. Е. С позиции 0x84 на) обратно в начало моего буфера?

Я серьезно пытался исследовать все это в течение достаточно долгого времени - но я новичок в.NET. Возможно, у потоков есть длинная, гордая (недокументированная) история, которую все остальные безоговорочно понимают. Но для новичка это все равно, что прочитать инструкцию к вашему автомобилю и узнать:

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

Технически верно, но серьезно, что мы хотим знать, так это то, что, если мы разбиваем это на пол, вы идетебыстрее..

РЕДАКТИРОВАТЬ - Большая картинка

У меня есть данные, поступающие из последовательного порта, сокета или файла, и у меня есть поток, который ждет там новых данных и записывает их в один или несколько потоков - все идентичные.
К одному из этих потоков я могу получить доступ из сеанса telnet с другого компьютера, и все это прекрасно работает.
Проблема, с которой я сталкиваюсь сейчас, заключается в анализе данных в коде в той же программе (в другом из дублированных потоков). Я дублирую данные в MemoryStream, и у меня есть поток, чтобы сидеть и расшифровывать данные, и передавать его обратно в пользовательский интерфейс. Эта тема делаетdataStream.BeginRead()в свой собственный буфер, который возвращает некоторое (?) количество данных до, но не больше, чемcountаргумент. После того, как я разобрался с тем, что я получил от BeginRead Я копирую оставшиеся данные (от конца моей точки чтения до конца потока) в начало моего буфера, чтобы он не переполнялся.
На данный момент, поскольку запись и чтение являются асинхронными, я не знаю, смогу ли я изменить позицию (так как это "курсор" - спасибо Джону). Даже если отправить сообщение в другой поток, чтобы сказать, что я только что прочитал 28 байтов, или что-то еще - он не будет знать, какие28 байтов они были, и не будет знать, как сбросить его курсор / position, Я не разделял потоки на подклассы - я только что создал MemoryStream и передал его потоку, который дублирует данные в те потоки, которые необходимы.

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

Как еще люди справляются с долговременным спорадическим потоком данных, который необходимо отправить для какой-то другой задачи, которая не является мгновенной для выполнения?


РЕДАКТИРОВАТЬ: вероятное решение

Пытаясь написать обертку Stream вокруг очереди из-за информации в ответах, я наткнулся на этот пост Стивена Туба.
Он написалBlockingStream и объясняет:

Большинство потоков в.NET Framework не являются потокобезопасными, а это означает, что несколько потоков не могут безопасно получить доступ к экземпляру потока одновременно, и большинство потоков поддерживают одну позицию, в которой произойдет следующее чтение или запись. BlockingStream, с другой стороны, является поточно-ориентированным и в некотором смысле неявно поддерживает две позиции, хотя ни одна из них не представляется в виде числового значения пользователю типа. BlockingStream поддерживает внутреннюю очередь записанных в него буферов данных. Когда данные записываются в поток, записанный буфер ставится в очередь. Когда данные считываются из потока, буфер удаляется в порядке "первым пришел-первым вышел" (FIFO), и данные в нем передаются вызывающей стороне. В этом смысле есть позиция в потоке, в которой будет происходить следующая запись, и позиция, в которой будет происходить следующее чтение.

Кажется, этоименно то , что я искал, так что, спасибо за ответы, ребята, я нашел это только из ваших ответов.

2 ответа

Решение

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

Давайте посмотрим, что говорится в документации:

Msgstr "При переопределении в производном классе получает или устанавливает позицию в текущем потоке."

Это "стандартная документация говорит" о том, что свойство предназначено для отслеживания позиции в потоке, но что Stream Сам класс не обеспечивает фактическую реализацию этого. Реализация заключается в классах, которые являются производными от Stream класс, как FileStream или MemoryStream, У каждого своя система поддержания позиции, потому что они работают против совершенно разных бэк-эндов.

Может даже быть реализация потоков, где Position собственность не имеет смысла. Вы можете использовать CanSeek свойство, чтобы узнать, поддерживает ли реализация потока позицию.

"Свойство Position не отслеживает количество байтов в потоке, которые были использованы, пропущены или оба".

Это означает, что Position Свойство представляет абсолютную позицию в реализации сервера, а не просто счетчик того, что было прочитано или записано. Методы для чтения и записи потока используют позицию, чтобы отслеживать, где читать или писать, это не наоборот.

Для реализации потока, которая не поддерживает позицию, она все равно могла бы вернуть, сколько байтов было прочитано или записано, но это не так. Position свойство должно отражать фактическое место в данных, и если оно не может этого сделать, оно должно бросить NotSupportedException исключение.

Теперь давайте посмотрим на ваш случай:

Используя StreamReader и StreamWriter против того же потока сложно, и в основном бессмысленно. Поток имеет только одну позицию, и она будет использоваться как для чтения, так и для записи, поэтому вам придется отслеживать две отдельные позиции. Кроме того, вам придется очищать буфер после каждой операции чтения и записи, чтобы в буферах и Position потока обновляется, когда вы получаете его. Это означает, что StreamReader а также StreamWriter не может использоваться по назначению, а действует только как обертка вокруг потока.

Если вы используете StreamReader а также StreamWriter из разных потоков, вы должны синхронизировать каждую операцию. Два потока никогда не могут использовать поток одновременно, поэтому необходимо выполнить операцию чтения / записи:

  • замок
  • установить позицию потока из локальной копии
  • читай пиши
  • буфер очистки
  • получить позицию потока в локальную копию
  • конец блокировки

Таким образом, поток можно использовать в качестве буфера FIFO, но есть и другие способы, которые могут лучше подходить для ваших нужд. Queue<T> например, работает как буфер FIFO в памяти.

  • Позиция является "курсором" как для письма, так и для чтения. Так что да, после сброса Position свойство 0, оно начнет перезаписывать существующие данные
  • Вы должны быть осторожны, когда имеете дело с потоком из нескольких потоков, если честно. Неясно, написали ли вы новый подкласс Stream или являетесь ли вы просто клиентом существующего потока, но в любом случае вам нужно быть осторожным.
  • Непонятно, что вы подразумеваете под "если я не обращаюсь с этим свойством" - что вы подразумеваете под "обрабатывать" здесь? Опять же, было бы полезно, если бы вы были более ясны в том, что вы делаете

Stream может действовать как труба... это действительно зависит от того, что вы делаете с ней. Непонятно, что вы подразумеваете под "нужно ли мне продолжать копировать данные после моего последнего чтения" - и неясно, что вы подразумеваете под своим буфером.

Если бы вы могли дать общее представление о том, чего вы пытаетесь достичь, это действительно помогло бы.

Другие вопросы по тегам