2011-01-15 10 views
9

(entero) La documentación de la propiedad position en una corriente dice:cómo hacer frente a la posición en la aC# corriente

  • Cuando se reemplaza en una clase derivada, obtiene o establece la posición dentro de la corriente corriente.
  • La propiedad Position no realiza un seguimiento del número de bytes de la secuencia que se han consumido, omitido o ambos.

Eso es todo. OK, así que estamos bastante claros en lo que no nos dice, pero realmente me gustaría saber de qué se trata realmente . ¿Cuál es 'la posición' para? ¿Por qué querríamos alterarlo o leerlo? Si lo cambiamos, ¿qué ocurre?

En un ejemplo práctico, tengo un flujo que periódicamente se escribe, y tengo un hilo que intenta leer de él (lo ideal es lo antes posible). Después de leer muchos problemas de SO, reinicié el campo position en cero para comenzar mi lectura. Una vez hecho esto:

  • ¿Esto afecta a dónde el escritor de esta secuencia intentará poner los datos? ¿Necesito hacer un seguimiento de la última posición de escritura? (es decir, si configuro la posición en cero para leer, ¿el escritor comienza a sobrescribir todo desde el primer byte?)
  • En caso afirmativo, ¿necesito un semáforo/bloqueo alrededor de este campo de "posición" (¿subclases, quizás?) debido a mis dos hilos accediendo a ella?
  • Si no gestiono esta propiedad, ¿el autor simplemente desborda el búfer?

Quizás no entiendo el Stream en sí mismo. Lo considero como un tubo FIFO: introducir datos en un extremo y extraerlos en el otro. Si es no como este, entonces ¿tengo que seguir copiando los datos más allá de mi última lectura (es decir, desde la posición 0x84 activada) hasta el inicio de mi memoria intermedia?

Intenté seriamente investigar todo esto por bastante tiempo, pero soy nuevo en .NET. Tal vez los Streams tienen una historia larga, orgullosa (indocumentada) que todos los demás comprenden implícitamente. Pero para un principiante, es como leer el manual de su automóvil y enterarse:

El pedal del acelerador afecta el volumen de combustible y aire enviado a los inyectores de combustible. No afecta el volumen del sistema de entretenimiento ni la presión de aire en ninguno de los neumáticos, si corresponde.

técnicamente cierto, pero en serio, lo que queremos saber es que si puré al suelo que vaya más rápido ..

EDIT - Bigger Picture

tengo datos ya sea desde un puerto serie, un socket o un archivo, y tienen un hilo que se encuentra allí esperando nuevos datos, y escribiéndolo en una o más secuencias, todas idénticas.
Una de estas transmisiones puedo acceder desde una sesión de telnet desde otra PC, y todo funciona bien.
El problema que estoy teniendo ahora es analizar los datos en el código en el mismo programa (en otra de las secuencias duplicadas). Estoy duplicando los datos en un MemoryStream, y tengo un hilo para sentarme y descifrar los datos, y volver a pasarlos a la IU. Este hilo hace un dataStream.BeginRead() en su propio búfer, que devuelve cierta (?) Cantidad de datos hasta, pero no más que, el argumento count. Después de tratar con todo lo que obtuve del BeginRead, copio los datos restantes (desde el final de mi punto de lectura hasta el final de la secuencia) al inicio de mi memoria intermedia para que no se desborde.
En este punto, dado que tanto la escritura como la lectura son asíncronas, no sé si puedo cambiar la posición (ya que es un 'cursor' - gracias Jon). Incluso si envía un mensaje al otro hilo para decir que acabo de leer 28 bytes, o lo que sea, no sabrá que 28 bytes eran, y no sabrá cómo restablecer su cursor/position. No he subclasificado ningún flujo: acabo de crear un MemoryStream y lo pasé al hilo que duplica los datos a los flujos necesarios.

Todo esto siente demasiado compleja para ser la forma correcta de hacerlo - sólo soy incapaz de encontrar un ejemplo sencillo que pueda modificar según sea necesario ..

¿Cómo, si no las personas a lidiar con un largo término de flujo de datos esporádicos que debe enviarse a alguna otra tarea que no sea instantánea para realizar?


EDIT: Solución probable

Al tratar de escribir una envoltura de secuencia alrededor de una cola, debido a la información en las respuestas, me topé this mensaje por Stephen Toub.
Ha escrito un BlockingStream, y explica:

mayoría de los arroyos en el .NET Framework no es seguro para subprocesos, lo que significa que múltiples hilos no pueden acceder con seguridad a una instancia de la corriente al mismo tiempo y la mayoría de los flujos de mantener un único posición en la que ocurrirá la siguiente lectura o escritura. BlockingStream, por otro lado, es seguro para subprocesos y, en cierto sentido, mantiene implícitamente dos posiciones, aunque ninguna de ellas se expone como un valor numérico para el usuario del tipo. BlockingStream funciona manteniendo una cola interna de búferes de datos escritos en ella. Cuando los datos se escriben en la secuencia, el búfer escrito se pone en cola. Cuando se leen los datos de la transmisión, un búfer se elimina de la cola en una orden de primero en entrar, primero en salir (FIFO), y los datos en ella se devuelven a la persona que llama. En ese sentido, hay una posición en la secuencia en la que se producirá la siguiente escritura y una posición en la que se producirá la siguiente lectura.

Esto parece exactamente lo que estaba buscando - así que gracias por los chicos answerrs, lo único que encontraron esto desde sus respuestas.

Respuesta

7

Creo que esperas demasiado de la documentación. Le dice exactamente lo que hace todo, pero no le dice mucho sobre cómo usarlo. Si no está familiarizado con las transmisiones, leer solo la documentación no le dará suficiente información para entender realmente cómo usarlas. mirada

Vamos a lo que dice la documentación:

"Cuando se reemplaza en una clase derivada, obtiene o establece la posición dentro de la corriente actual "

Ésta es "documentación estándar hablar" por decir que la propiedad está destinado a hacer el seguimiento de la posición en la corriente, pero que la clase Stream no proporciona la aplicación real de eso. La implementación se encuentra en las clases que se derivan de la clase Stream, como FileStream o MemoryStream. Cada uno tiene su propio sistema de mantenimiento de la posición, ya que trabajan contra extremos completamente diferentes.

Incluso puede haber implementación de transmisiones donde la propiedad Position no tiene sentido. Puede usar la propiedad CanSeek para averiguar si una implementación de flujo admite una posición.

"La propiedad de posición no mantiene la cuenta del número de bytes del flujo de que se han consumido, omitidos, o ambas cosas."

Esto significa que la propiedad Position representa una posición absoluta en la implementación de back-end, no es solo un contador de lo que se ha leído o escrito. Los métodos para leer y escribir la secuencia utilizan la posición para realizar un seguimiento de dónde leer o escribir, no es al revés.

Para una implementación de secuencia que no admite una posición, aún podría haber devuelto la cantidad de bytes que se han leído o escrito, pero no es así. La propiedad Position debe reflejar un lugar real en los datos, y si no puede hacerlo, debe lanzar una excepción NotSupportedException.

Ahora, vamos a ver su caso:

El uso de un StreamReader y una StreamWriter contra la misma corriente es difícil, y sobre todo inútil. La transmisión solo tiene una posición, y se usará tanto para lectura como para escritura, por lo que deberá realizar un seguimiento de dos posiciones separadas. Además, debería vaciar el búfer después de cada operación de lectura y escritura, de modo que no quede nada en los búferes y el Position de la transmisión esté actualizado cuando lo recupere. Esto significa que StreamReader y StreamWriter no se pueden usar según lo previsto y solo actúan como un contenedor alrededor de la ruta.

Si está utilizando el StreamReader y StreamWriter de diferentes temas, que tienen que sincronizar cada operación. Dos hilos no pueden utilizar la corriente al mismo tiempo, por lo que una operación de lectura/escritura tendrían que hacer:

  • bloqueo
  • posición
  • conjunto de la corriente de la copia local
  • lectura/escritura
  • búfer ras
  • posición get de la corriente de copia local
  • bloqueo final

Una secuencia se puede utilizar como un búfer FIFO de esa manera, pero hay otras formas que pueden ser más adecuadas para sus necesidades. Un Queue<T> por ejemplo funciona como una memoria intermedia FIFO en memoria.

+1

Montones de información, aquí, gracias. Después de sus dos últimos párrafos, comencé a escribir un contenedor de flujo alrededor de una cola, pero encontré una solución en mi investigación que debería funcionar: he añadido a mi pregunta – DefenestrationDay

+0

La documentación dice "Buscando en cualquier ubicación más allá de la longitud de la secuencia es compatible ". Esperaría que la documentación especifique qué sucede cuando buscamos más allá del final. ¿Se agrega al tamaño del archivo? Probablemente no, pero debería indicar explícitamente. – user34660

5
  • La posición es el "cursor" para escribir y leer. Entonces, sí, después de reiniciar la propiedad Position a 0, comenzará a sobrescribir los datos existentes
  • En primer lugar, debe tener cuidado al tratar con una secuencia de múltiples hilos, para ser honesto. No está claro si ha escrito una nueva subclase de Stream o si solo es el cliente de una transmisión existente, pero de cualquier forma debe tener cuidado.
  • No está claro a qué se refiere con "Si no manejo esta propiedad", ¿qué quiere decir con "manejar" aquí?Nuevamente, ayudaría si estuvieras más claro sobre lo que estabas haciendo.

Un Stream puede actuar como un tubo ... que realmente depende de lo que estás haciendo con él. No está claro a qué te refieres con "tengo que seguir copiando los datos después de mi última lectura", y tampoco estoy claro a qué te refieres con tu memoria intermedia.

Si pudiera dar una idea de la imagen más amplia de lo que está tratando de lograr, eso realmente ayudaría.

+0

Bien, gracias Jon. He agregado una imagen más grande, pero gracias por confirmar los problemas del cursor y sobrescribir. – DefenestrationDay

+0

@CapsicumDreams: Gracias por el fondo adicional. Parece que lo que realmente quieres es el equivalente de PipedInputStream/PipedOutputStream de Java. No conozco un equivalente en .NET (sin utilizar los PipeStreams que están realmente diseñados para IPC), pero es posible que desee considerar la construcción efectiva de una cola de productor/consumidor, donde cada elemento es una porción de datos. Si su hilo de lectura puede dividir los datos en mensajes significativos, tanto mejor. –

+0

Creo que he encontrado una solución; vea la respuesta adjunta. Gracias por su ayuda – DefenestrationDay

Cuestiones relacionadas