2010-04-26 21 views

Respuesta

20

A excepción de un bloqueo de la máquina, no, no puede perder datos. Sin embargo, es fácil usarlo mal y pensar que está perdiendo datos, ya sea porque una escritura no pudo escribir todos los datos que solicitó y no verificó el valor de retorno o porque hizo algo mal con la lectura.

La cantidad máxima de datos que puede contener depende del sistema: si intenta escribir más de eso, obtendrá una breve escritura o el escritor bloqueará hasta que haya espacio disponible. La página del manual pipe(7) contiene mucha información útil sobre las tuberías, que incluye (al menos en Linux) qué tan grande es el búfer. Linux tiene buffers de 4K o 64K dependiendo de la versión.

edición

Tim menciona SIGPIPE, que es también un problema potencial que puede parecer a perder datos. Si el lector cierra la tubería antes de leer todo en ella, los datos no leídos se descartarán y el escritor obtendrá una señal SIGPIPE cuando escriban más o cierren la tubería, lo que indica que esto ha ocurrido. Si bloquean o ignoran el SIGPIPE, recibirán un error EPIPE. Esto cubre la situación que Pablo mencionó.

PIPE_BUF es una constante que le dice que el límite de atomic escribe en el búfer. Cualquier escritura de este tamaño o menor tendrá éxito por completo o se bloqueará hasta que pueda tener éxito por completo (o le dará EWOULDBLOCK/EAGAIN si la tubería está en modo no bloqueante). No tiene relación con el tamaño real del buffer de tuberías del kernel, aunque obviamente el buffer debe tener al menos un tamaño PIPE_BUF para cumplir con la garantía de atomicidad.

+0

De hecho, abandoné mi respuesta después de cargar esta. Es posible que desee mencionar SIGPIPE, http://en.wikipedia.org/wiki/SIGPIPE –

+0

. ¿Puede haber un escenario en el que mata al escritor o al lector para que el escritor piense que está escrito algo que el lector no ha leído? –

+0

PIPE_BUF en limits.h le dirá qué tan grande es el límite. sysconf() con _PC_PIPE_BUF puede decirle en tiempo de ejecución (en Linux de todos modos) – frankc

2

Si se refiere a utilizar el operador | en el shell, entonces no, no perderá datos. Simplemente conecta la aplicación en el flujo de salida estándar del lado izquierdo a la aplicación en el flujo de entrada estándar del lado derecho. Si está canalizando datos entre aplicaciones y no obtiene los resultados que espera, intente usar > para redirigir la salida estándar de la primera aplicación a un archivo y luego use < para usar ese archivo como entrada estándar para la segunda aplicación. De esta forma, puede inspeccionar el archivo y asegurarse de que los datos se envíen en el formato que espera.

Si se refiere a una tubería creada por la función pipe, entonces la respuesta sigue siendo no. De acuerdo con this man page, escribir en una tubería completa se bloqueará hasta que se hayan leído suficientes datos para dejar espacio para los datos de escritura. También establece que el tamaño de una tubería es de 4 KB en Linux anterior a 2.6.11, y de 64 KB en 2.6.11 y posterior.

1

La razón por la que no perderá datos es que cuando el búfer asociado con el conducto se llena, una llamada al write se bloqueará hasta que el lector haya vaciado el búfer lo suficiente para que se complete la operación. (También puede realizar escrituras sin bloqueo, pero luego es responsable de asegurarse de completar las escrituras que se bloquearían).

2

Su tubería no está perdiendo datos. Si está perdiendo datos en su aplicación, intente depurarlo con gdb. Un par de cosas que debe buscar:
1) ¿Su memoria intermedia es lo suficientemente grande como para contener todos los datos que está leyendo?
2) Compruebe los códigos de retorno de su lectura() en la tubería para ver si hay errores.
3) ¿Estás seguro de que estás escribiendo todos los datos en la tubería?
4) ¿Su operación de escritura/lectura se ve interrumpida por una señal? es decir: ¿SIGPIPE?

3

datos se pueden perder en una tubería cuando ocurre lo siguiente:

  1. un proceso (el escritor) escribe n bytes de datos a la tubería, donde n≤ PIPE_BUF. Se garantiza que esta escritura sea atómica y nunca se bloqueará.
  2. Un proceso (el lector) solo lee m < n bytes de datos y salidas.
  3. El escritor no intenta volver a escribir en la tubería.

Como resultado, la memoria intermedia de la tubería del núcleo contendrá n-m bytes que se perderán cuando se hayan cerrado todos los identificadores de la tubería. El escritor no verá SIGPIPE o EPIPE ya que nunca intenta volver a escribir en la tubería. Dado que el escritor nunca aprenderá que la tubería contiene datos sobrantes que simplemente desaparecerán, uno puede considerar la pérdida de estos datos.

Una forma no estándar de detectar esto sería que el escritor defina un tiempo de espera y llame al FIONREAD ioctl para determinar el número de bytes que quedan en el buffer de tubería.

+0

¿No debería ser FIONREAD? Nota sobre Linux al menos FIONREAD indica la cantidad de datos que no se leen en el descriptor de escritura (stdout, por ejemplo), pero no parece indicar que el lector se haya ido. Me parece útil si hubiera un modo para que el núcleo envíe un SIGPIPE al escritor si el lector se fue sin leer todos los datos. – pixelbeat

+0

Gracias, corrigió el error tipográfico. De hecho, 'FIONREAD' no indica si el lector se ha ido, de ahí la necesidad de definir un tiempo de espera. Sí, también me resultaría útil si se enviara 'SIGPIPE'. – eigengrau82

Cuestiones relacionadas