2015-09-16 10 views
5

Ho difficoltà a capire perché il multithreading non riesce ad aggiornare i valori prima del completamento del thread. Il thread separato ha una propria copia dei riferimenti o dei valori?
Problema di multithreading che aggiorna il valore

In caso contrario, la mia comprensione il codice qui sotto dovrebbe funzionare correttamente quando MyMethod viene chiamato, ma spesso non creare istanze di alcuni oggetti MyType nella matrice prima della thread.IsAlive diventa falso:

class MyClass 
{ 
    static MyType[] obj = new MyType[Environment.ProcessorCount - 1]; 
    void MyMethod() 
    { 
     Thread[] threads = new Thread[Environment.ProcessorCount - 1]; 

     for (int i = 0; i < Environment.ProcessorCount - 1; i++) 
     { 
      threads[i] = new Thread(() => FillObjects(i)); 
      threads[i].Priority = ThreadPriority.AboveNormal; 
      threads[i].Start(); 
     } 

     while (threads[i].Any(c => c.IsAlive)) 
     { 
      Thread.Sleep(50); 
     } 
    } 
    void FillObjects(int i) 
    { 
     obj[i] = new MyType(); 
     //perform actions with obj[i] to fill it with necessary values 
    } 
} 

risposta

6

È necessario assegnare il valore della variabile loop a una variabile locale. In caso contrario, è possibile che la prima esecuzione di sia stata eseguita dopo l', pertanto non viene mai chiamato FillObjects(0) e pertanto non viene mai assegnato obj[0].

void MyMethod() 
{ 
    Thread[] threads = new Thread[Environment.ProcessorCount - 1]; 

    for (int i = 0; i < Environment.ProcessorCount - 1; i++) 
    { 
     int local = i; 
     threads[i] = new Thread(() => FillObjects(local)); 
     threads[i].Priority = ThreadPriority.AboveNormal; 
     threads[i].Start(); 
    } 

    while (threads.Any(c => c.IsAlive)) 
    { 
     Thread.Sleep(50); 
    } 
} 
+2

Buon punto. Se la prima istruzione in 'FillObjects()' fosse un 'Thread.Sleep (1000)' probabilmente solo 'obj [Environment.ProcessorCount - 1]' non sarebbe nullo perché il ciclo avrebbe incrementato 'i' al suo valore finale prima che venga creato il primo oggetto. Pensandoci, FillObjects() può essere lanciato perché 'i' effettivamente viene incrementato in' Environment.ProcessorCount-1' prima che il ciclo esca ed è quindi fuori dai limiti di 'obj'. –

+0

Grazie per la risposta, in effetti quello era uno dei maggiori problemi, ora crea un'istanza degli oggetti correttamente. Tuttavia il thread non completa tutte le operazioni correttamente prima che si chiuda e lo fa a caso. Eventuali suggerimenti? – Almis

+0

Ho trovato il mio errore logico, ora funziona correttamente. – Almis

-1

Su un computer multiprocessore (che è necessario disporre) i risultati scritti in una posizione di memoria in un thread potrebbero non essere visibili in un altro thread a causa della memorizzazione nella cache. Utilizzare Thread.VolatileRead e Thread.VolatileWrite leggere per leggere e scrivere "attraverso" la cache.

Cfr. the chapter on threading in c# 3.0 in a Nutshell per una spiegazione. (Cerca la domanda "È possibile che il metodo Wait scriva" False "?". Questo esempio è fondamentalmente il tuo caso.)

+0

Per curiosità: cosa c'è di sbagliato o non applicabile a ciò che ho detto? –

+0

Anche se non quello che ha downvoted: non riesco a pensare ad uno scenario per usare volatileRead/Write per risolvere il problema precedente. Il problema di riferimento da C# in IMHO in poche parole non corrisponde al problema precedente, così come non vedo alcun problema di caching che volatile risolverebbe. – Linky

+0

@Linky Hm. Sono due thread che accedono a una variabile statica. Un thread "ha scritto" su di esso (indicato da un evento più avanti in quel thread). L'altro thread legge il valore che è stato scritto dalla prospettiva del thread di scrittura e non vede la scrittura. Mi sembra molto simile allo scenario qui. –

Problemi correlati