2010-06-19 9 views
6

In base alla pagina man per read (2), restituisce zero solo quando EOF viene raggiunto.Può leggere (2) restituire zero quando non è in EOF?

Tuttavia, sembra che questo non sia corretto e che a volte può restituire zero, forse perché il file non è pronto per essere letto ancora? Dovrei chiamare select() per vedere se è pronto prima di leggere un file dal disco?

noti che nBytes è: 1.445.888

Alcuni codice di esempio:

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; 
    } 
} 

L'uscita legge (quando non riesce senza dati letti):

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

Questo è in esecuzione su CentOS4 32 bit come macchina virtuale utilizzando VMware Server 1.0.10. Il file system in lettura è locale alla macchina virtuale. Il computer host è Windows Server 2008 a 32 bit.

L'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 

mi accorgo che il link indicato di seguito http://opengroup.org/onlinepubs/007908775/xsh/read.html stati:

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. 

Così, forse io sono sempre un segnale di interruzione della lettura e quindi il valore restituito è zero a causa di un bug o pensa che siano stati letti zero byte?

+0

Non riesco a pensare perché restituire 0 quando non in EOF. Puoi fornire un esempio specifico di quando ciò accade? –

+0

Si verifica in circa uno su 50.000 tentativi identici. – WilliamKF

+0

Non è necessario selezionare select() sul descrittore di file. (Perché diavolo nel terzo millennio usi ancora select() e non il sondaggio() ??) I file sono sempre leggibili - non sono socket o dispositivi, non possono bloccare.Un po 'più di informazioni sul sistema - distro, versione del kernel, file system usato - potrebbero aiutare. – Dummy00001

risposta

1

Capito! Ho avuto un UMR (Uninitialized Memory Read) e cercavo erroneamente fino alla fine del file.

+0

Che cos'è l'UMR? – naive231

+0

È una lettura dalla memoria non inizializzata, in sostanza un valore "casuale". –

+0

@ naive231 UMR == Lettura non inizializzata della memoria. – WilliamKF

2

L'unico altro caso che posso pensare a read() restituendo 0 è se si passa in nbytes come 0; a volte ciò può accadere se si passa la dimensione di qualcosa o altro come parametro. Potrebbe essere quello che sta succedendo in questo momento?

Se il file non è pronto per essere letto, ciò che dovrebbe accadere è leggere restituisce -1 e errno è impostato su EAGAIN.

+0

nbytes non è zero. – WilliamKF

+0

Vedo ... in tal caso, probabilmente il problema è qualcosa di sottile * attorno * alla chiamata a read() piuttosto che alla chiamata stessa ... Sarei sorpreso se tale chiamata di sistema comune si rivelasse violata una delle sue postcondizioni di base. Puoi pubblicare più codice per vedere se c'è qualcosa di complicato in corso intorno ad esso? –

+0

Aggiunto codice di esempio. – WilliamKF

3

Dopo alcune ricerche, in realtà ci sono alcune circostanze in cui restituirà 0 che potresti non pensare come "EOF".

Per i dettagli grintosi, vedi la definizione POSIX per read(): http://opengroup.org/onlinepubs/007908775/xsh/read.html

Fra i più notevoli sono se chiedete per leggere 0 byte - doppio controllo che non sta passando accidentalmente 0 ad esso - - e la lettura oltre la fine della parte "scritta" del file (puoi effettivamente cercare oltre la fine del file, che "estende" il file con zero se scrivi lì, ma finché non lo fai, "EOF" è ancora alla fine della porzione già scritta).

La mia ipotesi migliore è che ci si trova in un problema di temporizzazione da qualche parte. Alcune domande che devi porre sono "Come vengono scritti questi file?" e "Sono sicuro che non sono a lunghezza zero quando cerco di leggerli?". Per il secondo, si potrebbe provare a eseguire una stat() sul file prima di leggerlo per vedere qual è la sua dimensione corrente.

+0

Il file è già su disco e stabile e viene letto solo, il file è lungo 50k. Gli nbytes non sono zero e stiamo leggendo dall'inizio del file. Chiamare stat() riporta 50k. – WilliamKF

+4

@WilliamKF: È davvero bizzarro. Sembra certo che potrebbe essere un bug del kernel/filesystem. Non sono nemmeno sicuro del modo migliore per isolare un caso come questo. Potrebbe essere necessario premere la mailing list linux-kernel o il canale IRC. Una cosa che potrebbe valere la pena provare è vedere se succede su un diverso tipo di filesystem. –

Problemi correlati