как бороться с позицией в потоке c # - PullRequest
10 голосов
/ 15 января 2011

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

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

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

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

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

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

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

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

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

РЕДАКТИРОВАТЬ - Увеличенное изображение

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

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

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

<ч />

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

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

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

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

Ответы [ 2 ]

7 голосов
/ 15 января 2011

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

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

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

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

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

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

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

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

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

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

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

  • lock
  • установить позицию потока из локальной копии
  • чтение / запись
  • буфер очистки
  • получение позиции потока для локальной копии
  • блокировка конца

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

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

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

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

...