2011-01-07 2 views
15

Ci sono molti articoli e discussioni che spiegano perché è bene costruire classi thread-safe. Si dice che se più thread accedono, ad es. un campo allo stesso tempo, ci possono essere solo alcune conseguenze negative. Quindi, qual è il motivo per mantenere il codice thread-safe non? Mi sto concentrando principalmente su .NET, ma credo che i motivi principali non dipendano dalla lingua.A cosa serve la sicurezza senza thread?

E.g. I campi statici .NET non sono thread-safe. Quale sarebbe il risultato se erano thread-safe per impostazione predefinita? (senza necessità di eseguire il blocco "manuale"). Quali sono i vantaggi dell'utilizzo (in realtà predefinito a) della sicurezza senza thread?

Una cosa che mi viene in mente è la performance (più di un'ipotesi, però). È piuttosto intuitivo che, quando una funzione o un campo non ha bisogno di essere thread-safe, non dovrebbe esserlo. Tuttavia, la domanda è: per cosa? La sicurezza del thread è solo una quantità aggiuntiva di codice che devi sempre implementare? In quali scenari posso essere sicuro al 100% che ad es. un campo non verrà utilizzato da due thread contemporaneamente?

risposta

15

la scrittura di codice thread-safe:

  1. richiede agli sviluppatori più esperti
  2. è più difficile e consuma sforzi più di codifica
  3. è più difficile per testare ed eseguire il debug
  4. solito ha più grande prestazione di costo

Ma! Il codice thread-safe non è sempre necessario. Se si può essere certi che a un determinato codice accederà solo un thread, l'elenco sopra riportato diventerà un sovraccarico enorme e non necessario. È come affittare un furgone quando si va in città vicina quando ci sono due di voi e non molti bagagli.

+0

Ma quando puoi dire che una DLL non userà mai il threading? E i clienti, che vorrebbero sperimentare con la tua libreria? Si dovrebbe rendere tutti i metodi pubblici thread-safe? Per quanto riguarda il furgone: alcune persone amano vantarsi. :) – pbalaga

+0

@rook: ricorda, se è una buona libreria non ti importa di come implementa le cose: non dovrebbe mai darti accesso a cose che sono poco sicure a meno che non le segnali molto attentamente per te. – Crisfole

+3

@rook: per quanto riguarda i client che fanno esperimenti con la loro libreria, a meno che non documenta esplicitamente che un metodo è thread-safe, è sicuro che non lo sia. I clienti si assumono la responsabilità di mantenere la sicurezza del thread durante l'utilizzo delle lezioni. – Juliet

11

La sicurezza della filettatura viene fornita con i costi: è necessario bloccare i campi che potrebbero causare problemi se si accede contemporaneamente.

Nelle applicazioni che non utilizzano thread, ma richiedono prestazioni elevate quando conta ogni ciclo di cpu, non c'è motivo di avere classi di thread sicure.

+0

Che tipo di problemi sono questi? Cosa succede se due thread eseguono solo operazioni di lettura su un campo? – pbalaga

+1

@rook: se due thread eseguono operazioni di lettura su un campo, leggeranno il valore del campo. Ora se entrambi i thread dicono di modificare il campo contemporaneamente, potresti avere problemi. –

5

Quindi, qual è il punto di mantenere il codice non thread-safe?

Costo. Come hai supposto, di solito c'è una penalità nella performance.

Inoltre, la scrittura di codice thread-safe è più difficile e richiede tempo.

5

La sicurezza del filo non è una proposizione "sì" o "no". Il significato di "sicurezza del filo" dipende dal contesto; significa "lettura concorrente sicura, scrittura concorrente non sicura"? Significa che l'applicazione potrebbe restituire dati obsoleti invece di bloccarsi? Ci sono molte cose che può significare.

Il motivo principale per non rendere un "thread safe" di classe è il costo. Se il tipo non sarà accessibile da più thread, non c'è alcun vantaggio nell'inserire il lavoro e aumentare i costi di manutenzione.

3

La scrittura del codice di sicurezza è a volte dolorosa. Ad esempio, il caricamento lazy semplice richiede due controlli per "== null" e un blocco. È davvero facile rovinare.

[EDIT]

Non volevo suggerire che filettati lazy loading è stato particolarmente difficile, è il "Oh, e io non ricordo di bloccare quella prima!" momenti che arrivano veloci e duri una volta che pensi di aver finito con il blocco che sono davvero la sfida.

+0

Anche questo è lento. THigns deve essere volatile, quindi il compilatore non ottimizza l'accesso. Volatile significa svuotamento della cache. Fondamentalmente l'elaborazione della CPU diventa molto più lenta. – TomTom

+0

@TomTom: assolutamente, sto solo dando la mia ragione principale per non fare le cose in parallelo tutto il tempo. Il tuo consumatore medio non si preoccupa troppo della velocità a meno che non se ne accorga, il che è piuttosto improbabile per la maggior parte delle applicazioni oggi. – Crisfole

+0

Ah, bello;) Vorrei poter avere questo lusso - lavorare con un sacco di dati o dati molto critici di tempo trasforma il mio punto di vista. – TomTom

2

Ci sono situazioni in cui "thread-safe" non ha senso. Questa considerazione si aggiunge alle maggiori capacità di sviluppo e al tempo maggiore (sviluppo, test e runtime portano tutti gli hit).

Ad esempio, List<T> è una classe non thread-safe comunemente utilizzata. Se dovessimo creare un equivalente thread-safe, come implementeremmo GetEnumerator? Suggerimento: non c'è una buona soluzione.

+0

Tuttavia, alcuni esistono ancora. Cosa c'è di sbagliato in queste implementazioni? – pbalaga

+0

Non sono sicuro di cosa intendi con "ancora alcuni esistono". L'unico modo per avere strutture dati veramente thread-safe è renderle immutabili. –

+0

In effetti, "ancora" deve essere eliminato. Quello che voglio dire è che esistono alcune soluzioni, che sembrano affrontare efficacemente il problema della sicurezza del thread. Forse non sono "bravi" come dici tu. – pbalaga

2

Quindi, qual è il punto di mantenere il codice non thread-safe?

Consentendo un codice non thread-safe, si lascia al programmatore decidere quale sia il livello corretto di isolamento.

Come altri hanno menzionato, ciò consente di ridurre la complessità e migliorare le prestazioni.

Rico Mariani ha scritto due articoli intitolati "Putting your synchronization at the correct level" e Putting your synchronization at the correct level -- solution che hanno un bell'esempio di questo in azione.

Nell'articolo ha un metodo chiamato DoWork(). In esso chiama altre classi Read due volte Write due volte e poi LogToSteam.

Read, Write e LogToSteam hanno tutti condiviso un blocco ed erano thread-safe. Ciò va bene, tranne il fatto che poiché DoWork era anche thread-safe, tutto il lavoro di sincronizzazione in ogni Read, Write e LogToSteam era una completa perdita di tempo.

Questo è tutto collegato alla natura Programmazione Imperativa. I suoi effetti collaterali ne causano la necessità.

Tuttavia, se si disponesse di una piattaforma di sviluppo in cui le applicazioni potessero essere espresse come funzioni pure in assenza di dipendenze o effetti collaterali, sarebbe possibile creare applicazioni in cui il threading è stato gestito senza l'intervento dello sviluppatore.

0

So, what is the point of keeping non thread-safe code?

La regola generale è quello di evitare di bloccare il più possibile. Il codice Ideal è re-entrant e thread-safe senza alcun blocco. Ma quella sarebbe utopia.

Tornando alla realtà, un programmatore good prova il suo livello al meglio per avere un blocco di sezione anziché bloccare l'intero contesto. Un esempio potrebbe essere il blocco di poche righe di codice alla volta in varie routine rispetto al blocco di tutto in una funzione.

Quindi, inoltre, si deve rifattorizzare il codice per ottenere un progetto che riduca al minimo il blocco se non lo elimina completamente.

ad es. considera una funzione foobar() che ottiene nuovi dati per ogni chiamata e utilizza switch() case per un tipo di dati per modificare un nodo in un albero. Il blocco può essere evitato per lo più (se non completamente) Poiché ogni dichiarazione di caso toccherebbe un nodo diverso in un albero. Questo potrebbe essere un esempio più specifico, ma penso che elabori il mio punto.

2

Girare questa domanda sulla sua testa.

All'inizio della programmazione non esisteva il codice thread-safe perché non esisteva il concetto di thread. Un programma è iniziato, quindi è proseguito passo dopo passo fino alla fine. Eventi? Cos'è quello? Le discussioni? Eh?

Quando l'hardware è diventato più potente, i concetti di quali tipi di problemi potrebbero essere risolti con il software sono diventati più fantasiosi e gli sviluppatori più ambiziosi, l'infrastruttura software è diventata più sofisticata. Inoltre è diventato molto più pesante. Ed eccoci qui, con un sofisticato ecosistema software sofisticato, potente e in alcuni casi inutilmente pesante che include thread e "thread-safety".

Mi rendo conto che la domanda è rivolta più agli sviluppatori di applicazioni che, ad esempio, agli sviluppatori di firmware, ma guardando all'intera foresta offre approfondimenti su come si è evoluto quell'albero.