2009-10-12 18 views
6

Ho usato la coda generica nella raccolta C# e tutti dicono che è meglio utilizzare l'oggetto di System.Collection.Generic.Queue a causa della sicurezza dei thread.Che cosa si intende per oggetto "thread safe"?

Si prega di indicare la giusta decisione per utilizzare l'oggetto Queue e come è thread-safe?

risposta

5

Un tipo protetto da thread può essere utilizzato in sicurezza da più thread senza problemi di concorrenza. Questo di solito significa che il tipo è di sola lettura.

Abbastanza interessante, Queue<T> è non thread-safe - è in grado di supportare letture simultanee fino a quando la coda non è modificato, ma che non è la stessa cosa come la sicurezza thread.

Per valutare la sicurezza dei thread, considerare cosa accadrebbe se due thread accedessero a uno Queue<T> e un terzo thread venisse a trovarsi e aggiungere o rimuovere da questo Queue<T>. Poiché questo tipo non limita questo comportamento non è thread-safe.

25

"Thread safe" è un termine un po 'sfortunato perché non ha una definizione solida. Fondamentalmente significa che certe operazioni sull'oggetto sono garantite per comportarsi in modo ragionevole quando l'oggetto viene gestito tramite più thread.

Considerare l'esempio più semplice: un contatore. Supponiamo di avere due thread che stanno incrementando un contatore. Se la sequenza di eventi va:

  • Thread uno legge dal contatore, ottiene zero.
  • Thread di due letture dal contatore, ottiene zero.
  • Il thread uno incrementa zero, scrive uno per il contatore.
  • Il thread due incrementi zero, scrive uno per il contatore.

Quindi notare come il contatore ha "perso" uno degli incrementi. Le semplici operazioni di incremento sui contatori non sono thread-safe; per renderli a prova di bug puoi usare i lock, o InterlockedIncrement.

Analogamente alle code. Le code non-thread-safe possono "perdere" accodare nello stesso modo in cui i contatori non-thread-safe possono perdere incrementi. Peggio ancora, le code non sicure possono persino bloccarsi o produrre risultati pazzeschi se le si utilizza in uno scenario multi-thread in modo errato.

La difficoltà con "thread safe" è che non è chiaramente definito. Significa semplicemente "non si blocca"? Significa che verranno prodotti risultati sensibili? Ad esempio, supponiamo di disporre di una raccolta "thread-safe". Questo codice è corretto?

if (!collection.IsEmpty) Console.WriteLine(collection[0]); 

No. Anche se la raccolta è "threadsafe", ciò non significa che questo codice sia corretto; un altro thread avrebbe potuto rendere la raccolta vuota dopo il controllo ma prima della linea di scrittura e quindi questo codice potrebbe bloccarsi, anche se l'oggetto è presumibilmente "thread-safe". Determinare effettivamente che ogni combinazione rilevante di operazioni è thread-safe è un problema estremamente difficile.

Ora per venire alla tua situazione attuale: chiunque ti stia dicendo "dovresti usare la classe Queue, è meglio perché è thread-safe" probabilmente non ha una chiara idea di cosa stiano parlando. Prima di tutto, Coda non è protetta da thread. In secondo luogo, se la coda è protetta da thread o non è completamente irrilevante se si sta usando l'oggetto su un singolo thread! Se si dispone di una raccolta a cui si accede su più thread, quindi, come indicato nel mio esempio sopra, si ha un problema estremamente difficile da risolvere, indipendentemente dal fatto che la raccolta stessa sia "threadsafe". È necessario determinare che ogni combinazione di operazioni eseguita sulla raccolta sia anche protetta da rischi. Questo è un problema molto difficile, e se è uno di quelli che affronti, allora dovresti usare i servizi di un esperto su questo argomento difficile.

+5

+1 Per la solida testimonianza di esperti. Hai anche ragione nel sottolineare che "thread safe" è un concetto piuttosto sfocato. –

+1

Mi piace come ogni domanda relativa alla sicurezza del thread abbia una risposta dallo stesso tipo, di cui ho letto la lettura per circa 2 ore. –

1

Nell'affrontare il multithreading, di solito si devono affrontare problemi di concorrenza. Il termine "problemi di concorrenza" si riferisce a problemi che sono specificatamente introdotti dalla possibilità di interleaving istruzioni da due diversi contesti di esecuzione su una risorsa condivisa da entrambi. Qui, in termini di sicurezza dei thread, i contesti di esecuzione sono due thread all'interno di un processo; tuttavia, in argomenti correlati potrebbero essere processi.

Le misure di sicurezza del filo sono state messe in atto per raggiungere principalmente due obiettivi. In primo luogo, è necessario riguadagnare il determinismo in relazione a ciò che accade se i thread interruttori di contesto (che sono altrimenti controllati dal sistema operativo e quindi fondamentalmente non deterministici nei programmi a livello utente), per impedire che alcune attività vengano lasciate a metà o due contesti scrivendo a la stessa posizione in memoria uno dopo l'altro. La maggior parte delle misure utilizza semplicemente un po 'di istruzioni test-and-set supportate da hardware e simili, così come il livello software synchronization constructs per forzare tutti gli altri contesti di esecuzione a stare lontano da un tipo di dati mentre un altro sta facendo un lavoro che non dovrebbe essere interrotto.

Di solito, gli oggetti di sola lettura sono thread-safe. Molti oggetti che non sono di sola lettura sono in grado di avere accessi ai dati (di sola lettura) che si verificano con più thread senza problemi, se l'oggetto non viene modificato nel mezzo. Ma questa non è la sicurezza del thread. La sicurezza del thread si verifica quando vengono eseguite tutte le operazioni su un tipo di dati per impedire che eventuali modifiche apportate da un thread causino il danneggiamento o il deadlock dei dati anche quando si utilizzano più letture e scritture simultanee.

Problemi correlati