Secondo MSDN ReadFile () funzione Win32 potrebbe erroneamente segnalare leggere il completamento dell'operazione. Quando?

StackOverflow https://stackoverflow.com/questions/2472810

Domanda

Gli stati MSDN nella sua descrizione della ReadFile() funzione:

  

Se hFile viene aperto con FILE_FLAG_OVERLAPPED, il parametro lpOverlapped deve puntare a una struttura OVERLAPPED valido e unico, altrimenti la funzione può segnalare erroneamente che l'operazione di lettura è stata completata.

Ho alcune applicazioni che violano la raccomandazione di cui sopra e vorrei conoscere la gravità del problema. Voglio dire il programma utilizza named pipe che è stato creato con FILE_FLAG_OVERLAPPED, ma si legge da esso utilizzando la seguente chiamata:

ReadFile(handle, &buf, n, &n_read, NULL);

Ciò significa che passa NULL come parametro lpOverlapped. Quella chiamata non dovrebbe funzionare correttamente in alcune circostanze in base alla documentazione. Ho speso un sacco di tempo a cercare di riprodurre il problema, ma non sono riuscito a! Ho sempre avuto tutti i dati nel posto giusto al momento giusto. Stavo testando solo named pipe però.

qualcuno dovrebbe sapere quando posso aspettarmi che ReadFile () in modo non corretto sarà tornare e segnalare il completamento con successo anche i dati non sono ancora nel buffer? Cosa dovrebbe succedere al fine di riprodurre il problema? Succede con i file, Bocchetta, console, o altri dispositivi? Devo usare particolare versione del sistema operativo? O particolare versione di lettura (come registrare la maniglia per porta di completamento I / O)? O particolare la sincronizzazione dei processi di lettura e scrittura / discussioni?

O quando vorrei che fallire? Funziona per me: /

Si prega di aiutare!

Per quanto riguarda, Martin

È stato utile?

Soluzione

Internamente il sistema supporta solo I / O asincrono. Per sincrono I / O del sistema crea una struttura OVERLAPPED temporanea hEvent = NULL;, emette una richiesta di I / O asincrono passando in questo temporaneo, e quindi attende per il completamento utilizzando GetOverlappedResult (BAttendere = TRUE) .

Ricordiamo che il hEvent della struttura OVERLAPPED temporanea è NULL e prestare attenzione alla sezione Osservazioni di GetOverlappedResult :

  

Se il membro hEvent della struttura OVERLAPPED è NULL, il sistema utilizza lo stato della maniglia hFile per segnalare quando l'operazione è stata completata.

Un file HANDLE è un oggetto che diventa waitable non segnalato quando inizia un'operazione di I / O, e ha segnalato quando un'operazione di I / O si conclude.

Ora consideriamo uno scenario in cui un file di HANDLE asincrono ha una richiesta di I / O in sospeso al momento si emette una richiesta di I / O sincrono. Il sistema crea una struttura OVERLAPPED e attende sul HANDLE hFile per il completamento. Nel frattempo la I / O asincrono completa, segnalando così la HANDLE causando sincrono I / O per ritornare prematuramente senza aver effettivamente completato.

peggio però è che dal momento in cui l'asincrono I / O che è stato avviato in risposta alla richiesta di I / O sincrono la completa aggiornerà la struttura OVERLAPPED temporaneo che non esiste più. Il risultato è la corruzione della memoria.

La storia completa è disponibile all'indirizzo The Old New Thing .

Altri suggerimenti

Sembra che ci si trova in una situazione in cui si sta deliberatamente chiamando un'API in violazione delle best practice documentate. In tali situazioni tutte le scommesse sono spenti. Si può lavorare, non può. Se può funzionare su questo sistema operativo, ma non sulla prossima iterazione del sistema operativo, o il prossimo service pack dello stesso sistema operativo. Cosa succede quando si porta a Win64? Sarà ancora lavorare allora?

Lo chiama GetLastError () (o guardando @ ERR, hr nel debugger) fornisce alcun valore che è utile in aggiunta al codice di errore?

Mi raccomando che si chiama con una struttura OVERLAPPED valida, farlo funzionare e togliere ogni dubbio (e possibilità di errore casuale). Perché avere il codice possibilmente buggy (e molto difficile da riprodurre bug) nel software quando si può risolvere il problema facilmente utilizzando una struttura OVERLAPPED valida?

Perché porre la domanda, piuttosto che fissare il codice per chiamare l'API come era previsto?

Ho il sospetto che sembra sempre a lavorare perché, anche se si tratta di un I / O asincrono, che completa molto rapidamente. A seconda di come si sta testando per il successo, è possibile che la funzione è erroneamente riporta che l'operazione è stata completata, ma si compie in realtà prima di testare i risultati.

La vera prova sarebbe quella di fare una lettura sul tubo prima che i dati di lì per essere letti.

Ma in realtà, si dovrebbe correggere il codice. Se la propria architettura non può gestire I / O asincrono, quindi rimuovere il FILE_FLAG_OVERLAPPED dalla creazione della named pipe.

Quando si dice

  

Blockquote   Se hFile viene aperto con FILE_FLAG_OVERLAPPED, il parametro lpOverlapped deve puntare a una struttura OVERLAPPED valido e unico, altrimenti la funzione può segnalare erroneamente che l'operazione di lettura è stata completata.

significano che non c'è nulla nel codice impedendole di lavoro, ma c'è anche un percorso attraverso il loro codice che può produrre risultati errati. Solo perché non è possibile riprodurre il problema con l'hardware particolare non significa che non c'è nessun problema.

Se davvero si vuole riprodurre il problema, lasciare il codice come è e andare avanti con la tua vita. Proprio nel momento che hai dimenticato tutto su questo problema, strano comportamento verrà a galla che non avrà alcuna relazione evidente a chiamare ReadFile. Potrai trascorrere giorni tirando i capelli, e il problema apparirà di andare e venire in modo casuale. Alla fine lo troverete e calci se stessi per non aver seguito le istruzioni. c'è stato, fatto quello, non è divertente!

L'altro modo di ricreare il problema è quello di programmare una demo importante per il vostro cliente. E 'sicuro di non riuscire poi!

Se non si desidera splatter il codice con strutture sovrapposta e tutti i relativi controlli di valore di ritorno, Waits, eventi, ecc, è possibile scrivere una funzione wrapper che prende una maniglia da cui leggere, e un timeout. Basta sostituire le chiamate a ReadFile con questo wrapper pratico-dandy.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top