I thread C # sono sicuri?

In particolare

  1. Crea una funzione per prendere un array e un indice come parametri.
  2. Crea un array di elementi.
  3. Crea un ciclo di conteggio.
  4. All’interno del ciclo su una nuova discussione assegnare una nuova istanza dell’object alla matrice usando l’indicizzatore passato.

So come gestire i thread ecc. Mi interessa sapere se questo è un modo sicuro per fare qualcosa.

class Program { // bogus object class SomeObject { private int value1; private int value2; public SomeObject(int value1, int value2) { this.value1 = value1; this.value2 = value2; } } static void Main(string[] args) { var s = new SomeObject[10]; var threads = Environment.ProcessorCount - 1; var stp = new SmartThreadPool(1000, threads, threads); for (var i = 0; i < 10; i++) { stp.QueueWorkItem(CreateElement, s, i); } } static void CreateElement(SomeObject[] s, int index) { s[index] = new SomeObject(index, 2); } } 

Credo che se ogni thread funziona solo su una parte separata dell’array, tutto andrà bene. Se hai intenzione di condividere dati (cioè di comunicarli tra thread), avrai bisogno di una sorta di barriera di memoria per evitare problemi con il modello di memoria.

Credo che se si generano una serie di thread, ognuno dei quali popola la propria sezione dell’array, quindi attendere che tutti quei thread finiscano usando Thread.Join , che farà abbastanza in termini di barriere affinchè tu sia sicuro . Al momento non ho documentazione di supporto per questo, badate bene …

EDIT: il tuo codice di esempio è sicuro. In nessun momento ci sono due thread che accedono allo stesso elemento: è come se ognuno di essi avesse variabili separate. Tuttavia, ciò non tende ad essere utile da solo. A un certo punto normalmente i thread vorranno condividere lo stato – un thread vorrà leggere ciò che un altro ha scritto. Altrimenti non ha senso scrivere in una matrice condivisa anziché nelle proprie variabili private. Questo è il punto in cui devi stare attento: il coordinamento tra i fili.

La documentazione MSDN sugli array dice:

I membri statici pubblici (Shared in Visual Basic) di questo tipo sono thread-safe. Non è garantito che tutti i membri di istanza siano thread-safe.

Questa implementazione non fornisce un wrapper sincronizzato (thread safe) per una matrice; tuttavia, le classi .NET Framework basate su Array forniscono la propria versione sincronizzata della raccolta utilizzando la proprietà SyncRoot.

L’enumerazione tramite una raccolta non è intrinsecamente una procedura thread-safe. Anche quando una raccolta è sincronizzata, altri thread possono ancora modificare la raccolta, il che fa sì che l’enumeratore generi un’eccezione. Per garantire la sicurezza del thread durante l’enumerazione, è ansible bloccare la raccolta durante l’intera enumerazione o rilevare le eccezioni risultanti dalle modifiche apportate da altri thread.

Quindi no, non sono sicuri.

Generalmente quando una raccolta viene definita “non protetta da thread”, ciò significa che gli accessi concorrenti potrebbero fallire internamente (ad esempio, non è sicuro leggere il primo elemento di List mentre un altro thread aggiunge un elemento alla fine dell’elenco: l’Elenco potrebbe ridimensionare l’array sottostante e l’accesso in lettura potrebbe andare al nuovo array prima che i dati siano stati copiati in esso).

Tali errori sono impossibili con gli array perché gli array hanno dimensioni fisse e non hanno tali “cambiamenti di struttura”. Un array con tre elementi non ha più o meno thread-safe di tre variabili.

Le specifiche C # non dicono nulla a riguardo; ma è chiaro se si conosce IL e si legge la specifica CLI: è ansible ottenere un riferimento gestito (come quelli utilizzati per i parametri “ref” C #) su un elemento all’interno di un array e quindi eseguire sia carichi normali che volatili e memorizzarli. La specifica CLI descrive le garanzie di sicurezza del filo per tali carichi e depositi (ad es. Atomicità per elementi < = 32 bit)

Quindi, se visualizzo correttamente la tua domanda, vuoi riempire un array usando thread diversi, ma assegnerai a ciascun elemento dell’array una sola volta? Se è così, è perfettamente sicuro per i thread.

L’esempio che stai fornendo è molto simile al modo in cui funzionano le estensioni Parallel di Microsoft al C # 4.0.

Questo per ciclo:

 for (int i = 0; i < 100; i++) { a[i] = a[i]*a[i]; } 

diventa

 Parallel.For(0, 100, delegate(int i) { a[i] = a[i]*a[i]; }); 

Quindi, sì, il tuo esempio dovrebbe essere OK. Ecco un vecchio post sul blog sul nuovo supporto parallelo in C #.