2010-06-19 11 views
6

De acuerdo con la página man para lectura (2), solo devuelve cero cuando se alcanza EOF.¿Puede leer (2) devolver cero cuando no está en EOF?

Sin embargo, parece que esto es incorrecto y que a veces puede regresar a cero, tal vez porque el archivo no está listo para ser leído todavía? ¿Debo llamar a select() para ver si está listo antes de leer un archivo del disco?

Tenga en cuenta que nBytes es: 1445888

un código de ejemplo:

fd_set readFdSet; 
timeval timeOutTv; 

timeOutTv.tv_sec = 0; 
timeOutTv.tv_usec = 0; 

// Let's see if we'll block on the read. 
FD_ZERO(&readFdSet); 
FD_SET(fd, &readFdSet); 

int selectReturn = ::select(fd + 1, &readFdSet, NULL, NULL, &timeOutTv); 

if (selectReturn == 0) { 
    // There is still more to read. 
    return false; // But return early. 
} else if (selectReturn < 0) { 
    clog << "Error: select failure: " << strerror(errno) << endl; 
    abort(); 
} else { 
    assert(FD_ISSET(fd, &readFdSet)); 

    try { 
    const int bufferSizeAvailable = _bufferSize - _availableIn; 

    if (_availableIn) { 
     assert(_availableIn <= _bufferSize); 

     memmove(_buffer, _buffer + bufferSizeAvailable, _availableIn); 
    } 

    ssize_t got = ::read(fd, _buffer + _availableIn, bufferSizeAvailable); 

    clog << " available: " << bufferSizeAvailable << " availableIn: " 
     << _availableIn << " bufferSize: " << _bufferSize << " got " 
     << got << endl; 

    return got == 0; 
    } catch (Err &err) { 
    err.append("During load from file."); 
    throw; 
    } 
} 

La salida lee (cuando se produce un error con leer ningún dato):

available: 1445888 availableIn: 0 bufferSize: 1445888 got: 0 

Esto se está ejecutando en CentOS4 32 bit como una máquina virtual utilizando VMware Server 1.0.10. El sistema de archivos que se lee es local para la máquina virtual. La máquina host es Windows Server 2008 de 32 bits.

El uname -a dice:

Linux q-centos4x32 2.6.9-89.0.25.ELsmp #1 SMP Thu May 6 12:28:03 EDT 2010 i686 i686 i386 GNU/Linux 

noto que el enlace que figura a continuación http://opengroup.org/onlinepubs/007908775/xsh/read.html estados:

The value returned may be less than nbyte if the number of bytes left in the file is less than nbyte, if the read() request was interrupted by a signal... 

If a read() is interrupted by a signal before it reads any data, it will return -1 with errno set to [EINTR]. 

If a read() is interrupted by a signal after it has successfully read some data, it will return the number of bytes read. 

Por lo tanto, tal vez estoy recibiendo una señal de interrupción de la lectura y por lo tanto el valor devuelto es cero debido a un error o cree que se leyeron cero bytes?

+0

No puedo pensar por qué devolvería 0 cuando no esté en EOF. ¿Puedes dar un ejemplo específico de cuándo sucede esto? –

+0

Ocurre en aproximadamente uno de cada 50,000 intentos idénticos. – WilliamKF

+0

No es necesario seleccionar() en el descriptor de archivo. (¿Por qué demonios en el 3er milenio aún usas select() y no el sondeo() ??) Los archivos siempre son legibles; no son sockets ni dispositivos, no pueden bloquearse.Un poco más de información sobre el sistema (distribución, versión del kernel, sistema de archivos utilizado) podría ser útil. – Dummy00001

Respuesta

1

¡Lo descubrí! Tenía una lectura de memoria no inicializada (UMR) y estaba buscando incorrectamente hasta el final del archivo.

+0

¿Qué es el 'UMR'? – naive231

+0

Es una lectura de la memoria no inicializada, esencialmente un valor "aleatorio". –

+0

@ naive231 UMR == Memoria no inicializada Lectura. – WilliamKF

2

El único otro caso que se me ocurre read() que devuelve 0 es si pasa nbytes como 0; a veces eso puede suceder si estás pasando el tamaño de algo u otro como un parámetro. ¿Podría ser eso lo que está sucediendo en este momento?

Si el archivo no está listo para leerse, lo que debería suceder es leer devuelve -1 y errno se establece en EAGAIN.

+0

nbytes no es cero. – WilliamKF

+0

Veo ... en ese caso, el problema probablemente sea algo sutil sucediendo * alrededor de * la llamada a read() en lugar de la llamada en sí ... Me sorprendería si una llamada al sistema tan común resultara violatoria una de sus postcondiciones básicas. ¿Puedes publicar más código para ver si hay algo complicado pasando al respecto? –

+0

Código de muestra agregado. – WilliamKF

3

Después de algunas investigaciones, en realidad hay algunas circunstancias en las que devolverá 0 que podría no considerar como "EOF".

Para los detalles arenosos, véase la definición POSIX para read(): http://opengroup.org/onlinepubs/007908775/xsh/read.html

Entre los más notables son, si se solicita para leer bytes 0 - vuelve a comprobar que usted no está pasando por accidente 0 a él - - y leer más allá del final de la parte "escrita" del archivo (en realidad puede buscar más allá del final del archivo, que "amplía" el archivo con ceros si escribe allí, pero hasta que lo haga, "EOF" está todavía al final de la parte ya escrita).

Mi mejor conjetura es que te estás metiendo en un problema de tiempo en alguna parte. Algunas preguntas que debe hacer son: "¿Cómo se están escribiendo estos archivos?" y "¿Estoy seguro de que no son de longitud cero cuando trato de leerlos?". Para el segundo, podría intentar ejecutar un stat() en el archivo antes de leerlo para ver cuál es su tamaño actual.

+0

El archivo ya está en el disco y es estable y solo se está leyendo, el archivo tiene 50k de longitud. Los nbytes no son cero y estamos leyendo desde el inicio del archivo. Llamar a stat() informa 50k. – WilliamKF

+4

@WilliamKF: Eso es realmente extraño. Seguro que parece que podría ser un error kernel/filesystem. Ni siquiera estoy seguro de la mejor manera de aislar un caso como este. Es posible que deba acceder a la lista de correo de linux-kernel o al canal IRC. Una cosa que valdría la pena intentar es ver si ocurre en un tipo diferente de sistema de archivos. –

Cuestiones relacionadas