2013-07-13 13 views
5

Ho il seguente codice che crea 10 thread che a sua volta scrivere messaggi alla console:variabili acquisite in ParameterizedThreadStart

for (int i = 0; i < 10; i++) 
{ 
    { 
     Thread thread = new Thread((threadNumber) => 
      { 
       for (int j = 0; j < 10; j++) 
       { 
        Thread.Sleep(200); 
        Console.WriteLine(string.Format("Thread: {0}, Line: {1}", threadNumber, j)); 
       }       
      }); 
     thread.Start(i); 
    } 
} 

mia comprensione è che ParameterizedThreadStart prende un oggetto per il quale viene inviata una copia del riferimento al thread. In tal caso, poiché non ho effettuato una copia locale di i all'interno di ciascun ciclo, tutti i nuovi thread punterebbero alla stessa posizione di memoria, il che significa che determinati numeri di thread potrebbero essere "persi". Avendo eseguito questo però (e anche contro un numero maggiore di thread/sleep time) ogni valore di i ha il suo thread. Qualcuno può spiegare perché?

risposta

4

Non è stato applicato nulla differito o "catturato" nel senso di creare una funzione anonima che avvolgerebbe i.

La funzione lambda qui non fa riferimento i da nessuna parte e il suo stato è completamente interiorizzato/conteneva quindi nessun problema qui:

(threadNumber) => 
{ 
    for (int j = 0; j < 10; j++) 
    { 
     Thread.Sleep(200); 
     Console.WriteLine(string.Format("Thread: {0}, Line: {1}", threadNumber, j)); 
    }       
}); 

Il Start chiamata qui:

thread.Start(i); 

Passi i per valore (cioè copia il suo valore) perché è un "tipo di valore" e non è catturato in alcun tipo di funzione anonima. In questo senso, viene passato come qualsiasi normale struct a qualsiasi metodo normale (perché questo è esattamente ciò che sta accadendo).


Se invece tu avessi scritto il tuo lambda come questo usando i al posto del tuo threadNumber:

{ 
    for (int j = 0; j < 10; j++) 
    { 
     Thread.Sleep(200); 
     Console.WriteLine(string.Format("Thread: {0}, Line: {1}", i, j)); 
    }       
}); 

allora si sarebbe nei guai. In questo caso, i si riferisce alla posizione della variabile originale e verrà valutata ogni volta che viene eseguito il thread. Ciò significa che potrebbe essere il valore corrente di i quando è stato creato (improbabile solo a causa dei tempi di elaborazione) o il valore impostato più avanti nel ciclo for o l'ultimo valore possibile 10 e probabilmente il numero salta o condiviso tra iterazioni.

+0

Grazie per la spiegazione dettagliata Chris, è stata la copia in base al valore che mi stava facendo incazzare! – Maverick

+0

@ Nota di salvataggio anche nel caso di "errore" che dà, è comunque possibile ottenere il risultato corretto aggiungendo una riga 'var i1 = i' prima della chiusura e usando' i1' ovunque si usi 'i'. – lobsterism