2010-08-28 7 views
11

Un socket può essere chiuso da un altro thread quando è in corso una trasmissione/ricezione sullo stesso socket?Un socket può essere chiuso da un altro thread quando una send/recv sullo stesso socket è attiva?

Supponiamo che un thread stia bloccando la chiamata recv e che un altro thread chiuda lo stesso socket, il thread nella chiamata recv lo sappia e uscirà sicuro?

Vorrei sapere se il comportamento sarà diverso tra diversi sistemi operativi/piattaforme. Se sì, come si comporterà in Solaris?

risposta

2

Non conosco l'implementazione dello stack di rete Solaris, ma butto fuori la mia teoria/spiegazione del perché dovrebbe essere sicuro.

  • Il thread A inserisce una chiamata di sistema di blocco, ad esempio read(2), per questo socket specificato. Non ci sono dati nel buffer di ricezione socket, quindi il thread A viene rimosso dal processore e messo in coda di attesa per questo socket. Nessun evento di stack di rete viene avviato qui, lo stato della connessione (presupponendo TCP) non è cambiato.
  • Thread B problemi close(2) sulla presa. Mentre la struttura del socket del kernel dovrebbe essere bloccata mentre il thread B sta accedendo ad essa, nessun altro thread è in possesso di quel lock (il thread A ha rilasciato il lock quando è stato messo in sleep-wait). non ci Supponendo che sono dati in sospeso nel buffer di invio socket, un pacchetto FIN viene inviato e la connessione entra nello stato FIN WAIT 1 (nuovo presumo TCP qui, vedere connection state diagram)
  • Sto indovinando che il cambiamento di stato connessione socket genererebbe un wakeup per tutti i thread bloccati su un dato socket. Quello è il thread A entrerebbe in uno stato eseguibile e scoprirà che la connessione si sta chiudendo. L'attesa potrebbe essere reinserita se l'altra parte non ha inviato il proprio FIN, altrimenti la chiamata di sistema restituirebbe con eof in caso contrario.

In ogni caso, le strutture interne del kernel saranno protette da accessi concorrenti inappropriati. Ciò non significa che sia una buona idea eseguire I/O socket da più thread. Vorrei consigliare di esaminare socket non bloccanti, macchine a stati e framework come libevent.

0

Sì, è possibile chiudere il socket da un altro thread. Qualsiasi thread bloccato/occupato che utilizza quel socket segnalerà un errore appropriato.

+6

In linux atleast non sembra segnalare così. Un thread recv bloccato rimane bloccato, anche se chiamiamo close da un altro thread. – Jay

2

Per me, shutdown() presa da un altro thread farà il lavoro in Linux

+2

Benvenuti in stackoverflow.com. Puoi migliorare la tua risposta fornendo un riferimento ad una sorta di documentazione che asserisce questo o fornisce un breve esempio. Una risposta che "funziona per te" non è utile, perché non può funzionare per gli altri. – stefan

1

Se un thread è bloccato su recv() o send() quando il socket è chiuso da un filo differente, il filo bloccato riceverà un errore. Tuttavia, è difficile rilevare l'azione correttiva corretta dopo aver ricevuto l'errore. Questo perché il numero del descrittore di file associato al socket potrebbe essere stato prelevato da un thread diverso e il thread bloccato è stato risvegliato in un errore per un socket "valido". In tal caso, il thread svegliato deve essere non chiamata close().

thread attivato dovrà qualche modo a distinguere se l'errore è stato generato dal collegamento (ad esempio un errore di rete) che per chiamare close(), o se l'errore è stato generato da un diverso thread, chiamati close() su di essa , nel qual caso dovrebbe solo passare l'errore senza fare altro fino alla presa.

3

In Linux la chiusura di una presa non si attiva recv().Inoltre, come @jxh dice:

Se un thread è bloccato su recv() o send() quando il socket viene chiuso da un filo differente, il filo bloccato riceverà un errore. Tuttavia, è difficile rilevare l'azione correttiva corretta dopo che ha ricevuto l'errore. Ciò è dovuto al fatto che il descrittore di file numero associato al socket potrebbe essere stato prelevato da un altro thread e che il thread bloccato è stato risvegliato in un errore per un socket "valido" . In tal caso, il thread di benvenuto non dovrebbe chiamare lo stesso close().

thread attivato dovrà qualche modo a distinguere se l'errore stato generato dal collegamento (ad esempio un errore di rete) che richiede per chiamare close(), o se l'errore è stato generato da un thread diverso avendo chiamato close() su di esso, nel qual caso si dovrebbe solo errore fuori senza fare nulla di più al socket.

Quindi il modo migliore per evitare entrambi i problemi è chiamare shutdown() anziché close(). shutdown() renderà il descrittore di file ancora disponibile, quindi non verrà assegnato da un altro descrittore, inoltre si sveglierà con un errore recv() e il thread con la chiamata recv() può chiudere il socket in modo normale, come un normale errore.

Problemi correlati