2012-03-25 17 views
5

È sicuro se voglio chiamare closesocket() su un socket del server da 1 thread che è separato da un altro thread che esegue il server utilizzando lo stesso socket del server?Il thread closesocket è sicuro?

+2

Si potrebbe voler ripensare * perché * si hanno più thread che accedono allo stesso socket. Forse potrebbe essere meglio avere un flag di stato che possa * informare * gli altri thread che una connessione sta morendo, ma solo un thread effettivamente interagisce con il socket. –

+0

@KerrekSB: in genere, c'è più di un thread che accede al socket perché un thread esegue il blocco delle letture e un altro thread scrive. Questo è sicuro/normale. Un flag di stato non è utile se il/i thread/i sono bloccati nelle chiamate di blocco. –

+0

@MartinJames: anche se questa pratica è "sicura" dal punto di vista del socket, è molto difficile ottenere quello scenario giusto (almeno, è molto più difficile di quanto sembri a prima vista), proprio perché c'è molta difficoltà nella sincronizzazione thread bloccati in una chiamata bloccante. In ogni caso, il design dell'applicazione dovrebbe rendere evidente chi possiede il socket e "chi finisce per ultimo" è davvero una buona scelta. –

risposta

5

La chiamata stessa è thread-safe, ma la pratica non lo è. Ogni volta che stai deallocando una risorsa il cui identificatore può essere riutilizzato dopo essere stato deallocato, devi sincronizzarlo con tutti i thread che potrebbero usarlo. Altrimenti, è possibile che, dopo che la risorsa è stata deallocata, una nuova risorsa (nel tuo caso, socket) potrebbe essere allocata con lo stesso identificativo (numero di socket) e il codice che intende accedere al socket del server (ora chiuso) potrebbe finire operativo su una presa diversa.

Il grado in cui questo è pericoloso (e se può accadere del tutto) dipende molto dal codice. Potrebbe non succedere se non si creano più socket dopo aver chiuso il socket del server. Ma è concettualmente molto sbagliato, e chiunque riesame il tuo codice lo considererebbe molto negativo.

Modifica: La soluzione a problemi di questo tipo è la protezione del descrittore di risorse (non della risorsa stessa) con un blocco lettore-scrittore (rwlock). L'accesso al descrittore di risorse (la variabile intera che contiene il numero di socket, nel tuo caso) richiede di mantenere un blocco "di lettura" su di esso, sia che tu stia eseguendo l'input o l'output o altro utilizzando la risorsa a cui fa riferimento. La deallocazione della risorsa (e la memorizzazione di un valore sentinella come -1 nella variabile che contiene il descrittore) richiede un blocco di scrittura.

+0

Ecco a cosa serve "TIME_WAIT". Se esiste una mappatura di livello superiore (ad esempio una libreria socket assegna un oggetto contesto socket) e non riesce a garantire che tali contesti non possano essere riutilizzati, ciò non rientra nell'ambito della domanda OP. Se questo approccio è considerato sbagliato, allora forse qualcuno potrebbe suggerire un'alternativa (una che non prevede la riprogettazione di un server di sincronizzazione come asincrona e non richiede un timeout di breve durata della CPU sul socket per controllare un flag). –

+1

No, non è completamente correlato a 'TIME_WAIT'. Non sto parlando della * porta * che viene riutilizzata, il che non è un problema. Sto parlando del * numero di socket * (su POSIX questo sarebbe un descrittore di file, ma su Windows sono separati), che è un intero locale del processo che identifica un socket aperto, che viene riutilizzato. Questo non ha assolutamente nulla a che fare con 'TIME_WAIT'. –

+0

È correlato, sebbene non direttamente. È una risorsa in cui potrebbe esserci qualche dubbio su quando può essere riutilizzato.Un modo comune per risolvere questo problema consiste nel mettere la risorsa su una coda di timer finché non è oltre ogni ragionevole possibilità che il riutilizzo possa causare un problema (TCP TIME_WAIT). Nel caso delle maniglie di presa, il problema è normalmente persino facile da controllare senza timeout, ad es. rimuovendo il manico da qualsiasi lista di sicurezza thrad in cui si trova. Solo perché qualcosa può essere usato impropriamente non significa che non si dovrebbe mai farlo, soprattutto se non esiste un'alternativa ragionevole. –

1

Sì, non è un problema. Naturalmente, ci saranno eccezioni/errori generati negli altri thread che hanno chiamate in sospeso sul socket, ma lo stack di rete stesso, (che deve essere thread-safe a causa di tutti i processi/thread che lo utilizzano normalmente), non sarà danneggiato.