2012-10-08 15 views

risposta

11

Il la prima chiamata dovrebbe restituire 0; la seconda chiamata deve restituire -1 e impostare errno su EBADF.

È necessario impedire che la seconda chiamata accada impostando fd a un numero errato noto, ad es. un -1 subito dopo la prima chiamata di close, e successivamente il controllo fd prima di effettuare la seconda chiamata (e non effettuare la chiamata se fd è -1):

close(fd); 
fd = -1; 
... 
// More code 
... 
if (fd != -1) { 
    close(fd) 
    fd = -1; 
} 

Questo modello di codice vi aiuterà quando è necessario effettuare chiamate verso close da più posizioni, ma non si è sicuri se il file è aperto o se è già stato chiuso. Passare da -1 a close è innocuo (si otterrebbe uno EBADF, ovviamente).

+0

Perché dovresti evitare che la seconda chiamata accada? –

+0

Impostare fd su -1 non ha alcun effetto (certamente non "impedisce che la seconda chiamata accada") ... sia quella che una fd chiusa rendimento EBADF –

+5

@JimBalter impostando da fd a -1 si eviterebbe il rischio di chiudere occasionalmente un file un altro thread appena aperto. – simonc

7

Dovrebbe essere innocuo a meno che non si sta filettata o fare qualcosa fra le due chiamate di chiudere. Quindi potresti finire per chiudere un file che è stato aperto da qualcos'altro nel tuo programma.

Il modo in cui il threading è rilevante è che le librerie quasi sempre fanno cose strane alle vostre spalle. Libc aprirà i file per cercare i messaggi di errore o altre cose dipendenti dalla localizzazione, il resolver può aprire i file di configurazione, ecc. Se chiudi un descrittore di file e lo chiudi di nuovo, in un ambiente con thread puoi facilmente finire in una situazione in cui il file il descrittore è stato riutilizzato da una biblioteca e lo si chiude dietro la schiena.

+0

+1 per menzionare possibili problemi in un ambiente con thread. – alk

+0

La * prima * chiamata alla chiusura potrebbe chiudere un file da un altro thread. Due chiusure non sono rilevanti per quel problema. L'unico modo in cui il threading è rilevante qui è che il secondo potrebbe non fallire dopo tutto se quel file fd è stato riaperto, ma non è interessante ... se non sincronizzi i tuoi thread possono accadere tutti i tipi di cose brutte. –

+2

Il valore restituito da 'open()' viene riciclato dal sistema operativo. Quindi se il thread A ha chiamato 'open()' e ha ottenuto fd = 3, quindi 'close() è s. Quindi, poco prima che il thread A chiamasse 'close()' la seconda volta, il thread B ha chiamato 'open()' con successo e ha ottenuto fd = 3 di nuovo. Quindi quale sarebbe il secondo 'close()' chiamato dal thread A do? – alk

1

Se il fd valore di pf rimane lo stesso la seconda chiamata restituirà un errore che il fd non è valido (EBADF - come dasblinkenlight sottolineato)

pensare di fare quacosa likg

if fd != -1) 
{ 
    close (fd); 
    fd = -1; 
} 
+1

Questo tipo di cose non ha senso, poiché close (fd) non è indefinito o comunque pericoloso quando fd è già chiuso ... close (fd) e close (-1) fanno esattamente la stessa cosa. L'unica ragione per impostare fd su -1 è assicurarsi che non sia un descrittore di file aperto valido come 0. –

+0

Ok, la gente ha notato che un descrittore di file potrebbe essere stato riaperto in un altro thread, quindi impostando fd = -1 è una buona pratica. Ma il test 'fd! = -1' non è strettamente necessario ... l'effetto è lo stesso senza di esso. –

+1

Sono d'accordo con te che il test per -1 non è necessario. Ancor più: in un debug-build lo ometterei, e registro l'errore 'close()' tornerebbe quindi, per indicarmi il casino che ho creato che porta a provare a chiudere il file due volte ... ;-) @ JimBalter – alk

3

La seconda chiamata avrà esito negativo con Errno: EBADF quando perché, a questo punto, fd non è un descrittore di file attivo.

Non dovrebbe avere alcun effetto sull'esecuzione. Tuttavia, se un numero di errore è stato impostato dalla prima chiusura, questo andrà perso, quindi non si dovrebbe chiudere due volte il descrittore di file.

+0

Ah, questa risposta dice in realtà qualcosa di valido! +1 –

4

Chiusura del stessa FD due volte dovrebbe essere non-fatale, come altri hanno fatto notare, ma attenzione di codice come questo

close(fd); 
/* ... */ 
newfd = open(....); 
/* ... */ 
close(fd); 

Con il secondo vicino, non si può essere sicuri se è in realtà fd lo stesso di newfd! Ciò porterebbe a crash ogni volta che si tenta di utilizzare newfd.

Quindi (se c'è il codice tra le due chiamate close) non è sicuro farlo. Sempre i descrittori di file close esattamente una volta.Sempre i buffer free esattamente una volta.

Problemi correlati