2009-02-12 13 views
24

Qual è il comportamento della funzione select(2) quando un descrittore di file che sta guardando per la lettura è chiuso da un altro thread?Cosa fa select (2) se si chiude (2) un descrittore di file in un thread separato?

Da alcuni test rapidi, viene restituito immediatamente. Sospetto che il risultato sia che (a) continui ad aspettare i dati, ma se provassi effettivamente a leggerli otterresti EBADF (probabilmente - c'è una potenziale razza) o (b) che finge come se il descrittore di file non è mai stato inoltrato. Se quest'ultimo caso è vero, passare in un unico file fd senza timeout causerebbe un deadlock se fosse chiuso.

+0

Possibile duplicato di [estrazione dalla selezione socket] (http://stackoverflow.com/questions/2486727/breaking-out-from-socket-select) – iammilind

+0

Penso che sia diverso, anche se leggermente correlato. L'altra domanda sta chiedendo esplicitamente come uscire da un 'select()' da un altro thread (e 'pipe()' è una buona risposta), mentre il mio era più sul comportamento di 'close()' su un 'select () Presa 'ed. Nelle risposte qui sotto, vedrai che la risposta è "dipende". –

+0

Una delle più misteriose cacce agli insetti che ho seguito si è rivelata dovuta a questo problema: il thread A stava selezionando sul socket #x, quale thread B era chiuso. Poco dopo, il thread C ha creato un nuovo socket, che era anche il socket n. X (perché lo stack di rete ha scelto di riutilizzare il numero x per il nuovo socket). A questo punto il thread A (che stava ancora tentando di usare socket #x) ha ovviamente iniziato a selezionare/leggere/scrivere dati sul socket del thread C, anche se non avevano assolutamente nessuna connessione logica tra loro. Questo è stato un dolore totale da rintracciare. –

risposta

21

da alcune ulteriori indagini, sembra che sia DWC e bothie hanno ragione.

bothie's answer alla domanda si riduce a: è un comportamento non definito.Ciò non significa necessariamente che sia imprevedibile, ma che sistemi operativi diversi lo fanno diversamente. Sembrerebbe che sistemi come Solaris e HP-UX ritorno da select(2) in questo caso, ma Linux non basate su this post to the linux-kernel mailing list dal 2001.

L'argomento sulla mailing list linux-kernel è essenzialmente che non è definito (e rotti) comportamento su cui fare affidamento. Nel caso di Linux, chiamare close(2) sul descrittore di file diminuisce efficacemente un conteggio di riferimento su di esso. Poiché esiste una chiamata select(2) anche con un riferimento ad essa, il file fd rimarrà aperto e in attesa di input fino al select(2) restituisce. Questo è fondamentalmente dwc's answer. Otterrai un evento sul descrittore del file e quindi verrà chiuso. Provare a leggere da esso comporterà un EBADF, assumendo che il file fd non sia stato riciclato. (Una preoccupazione che MarkR ha fatto in his answer, anche se penso che sia probabilmente evitabile nella maggior parte dei casi con una sincronizzazione corretta.)

Quindi grazie per l'aiuto.

+0

È necessariamente imprevedibile. Non esiste un modo prevedibile per "chiudere" un descrittore di file in un thread mentre un altro thread lo sta guardando per la lettura in "select" perché non è possibile che il thread che chiama "close" possa sapere se l'altro thread è già bloccato in 'select' o in procinto di bloccare in' select'. –

6

Mi aspetto che si comporti come se la fine del file fosse stata raggiunta, vale a dire, sarebbe ritornata con il descrittore di file mostrato come pronto ma qualsiasi tentativo di leggerlo successivamente restituirebbe "descrittore di file errato ".

Detto questo, farlo è molto cattiva pratica in ogni caso, come ci ha sempre potenziali condizioni di gara come un'altra descrittore di file con lo stesso numero potrebbe essere aperto da un altro filo immediatamente dopo l'altro secondo la chiuse, quindi il thread di selezione finirebbe per attendere quello sbagliato.

Appena si chiude un file, il suo numero diventa disponibile per il riutilizzo e può essere riutilizzato dalla prossima chiamata a open(), socket() ecc., Anche se da un altro thread. Quindi hai davvero bisogno di evitare questo genere di cose.

+0

Ho pensato che potesse essere anch'esso pronto, ma non è corretto: il descrittore non è effettivamente pronto - è chiuso. E come dici, quando andrai a usarlo potrebbe essere riassegnato a qualcos'altro. –

+0

Si può evitare la gara usando un mutex per la struttura dati che contiene il fd, però. Ma funzionerebbe solo se la chiamata select() avesse un timeout definito. –

2

E 'un po' di confusione quello che stai chiedendo ...

Select() dovrebbe restituire su un cambiamento "interessante". Se il close() ha semplicemente decrementato il conteggio dei riferimenti e il file era ancora aperto per la scrittura da qualche parte, non c'è motivo per selezionare() per svegliarsi.

Se l'altro thread è stato chiuso() sull'unico descrittore aperto, diventa più interessante, ma dovrei vedere una versione semplice del codice per vedere se qualcosa è veramente sbagliato.

5

La chiamata di sistema selezionata è un modo per attendere che i descrittori di file cambino stato mentre i programmi non hanno altro da fare. L'uso principale è per le applicazioni server, che aprono una serie di descrittori di file e quindi attendono qualsiasi cosa da fare (accettare nuove connessioni, leggere richieste o inviare le risposte). Questi descrittori di file verranno aperti in modalità io non bloccante in modo tale che il processo del server non si blocchi in un syscall in qualsiasi momento.

Ciò significa inoltre che non è necessario utilizzare thread separati, poiché tutto il lavoro, che è possibile eseguire nel thread, può essere eseguito anche prima della chiamata selezionata. E se il lavoro richiede molto tempo, che può essere interrotto, selezionare essere chiamato con timeout = {0,0}, i descrittori di file vengono gestiti e in seguito il lavoro viene ripreso.

Ora si chiude un descrittore di file in un'altra discussione. Perché hai quel filo in più e perché chiuderà il descrittore di file?

Lo standard POSIX non fornisce alcun suggerimento, cosa succede in questo caso, quindi quello che stai facendo è UN COMPORTAMENTO NON DEFINITO. Aspettatevi che il risultato sarà molto diverso tra i diversi sistemi operativi e anche tra la versione dello stesso sistema operativo.

saluti, Bodo

+1

Penso che avrà comunque un comportamento indefinito, perché è impossibile rimuovere la condizione di competizione del descrittore di file che viene chiuso * poco prima * la selezione e un'altra aperta con lo stesso numero. – MarkR

Problemi correlati