2015-12-16 16 views
7

Quando si avviano più thread, il parametro id viene analizzato a volte errato. Qui è la mia startup:Parametri della filettatura modificati

for (int i = 0; i < _threadCount; i++) 
{ 
    Thread thread = new Thread(() => WorkerThread(i)); 
    thread.Start(); 
    _threads.Add(thread); 
} 

E la mia funzione di discussione:

private void WorkerThread(int id) 
{ 
    Console.WriteLine("[{0}] Thread started {1}", DateTime.Now.ToLongTimeString(), id); 
} 

L'uscita di questo codice è:

[19:10:54] Thread start 3 
[19:10:54] Thread start 9 
[19:10:54] Thread start 4 
[19:10:54] Thread start 12 
[19:10:54] Thread start 11 
[19:10:54] Thread start 3 
[19:10:54] Thread start 12 
[19:10:54] Thread start 6 
[19:10:54] Thread start 9 
[19:10:54] Thread start 6 
[19:10:54] Thread start 13 
[19:10:54] Thread start 2 
[19:10:54] Thread start 15 
[19:10:54] Thread start 9 
[19:10:54] Thread start 15 

Dove nella mia mente, questo codice dovrebbe creare ogni thread con un unico id invece di duplicati come visto sopra.

Compiler informazioni: obiettivo

Piattaforma: x64

target Framework: .NET Framework 4.5

+2

Tutti i thread condividono la stessa variabile. – SLaks

+0

Qualcuno in realtà ha appena postato una domanda simile, ecco un articolo collegato di Eric Lippert sull'argomento. http://ericlippert.com/2009/11/12/close-over-the-loop-variable-considered-harmful-part-one/ – KDecker

risposta

9

Si dovrebbe fare attenzione su come modificare accidentalmente catturati variabili come i dopo l'inizio del filo, in quanto il i è condiviso. La variabile i si riferisce alla stessa posizione di memoria per tutta la durata del ciclo. La soluzioneè utilizzare un temporaneo variabile simili:

for (int i = 0; i < _threadCount; i++) 
{ 
     var i1 = i; 
     Thread thread = new Thread(() => WorkerThread(i1)); 
     thread.Start(); 
     _threads.Add(thread); 
} 

più informazioni Chiusure qui: The Beauty of Closures from (Jon Skeet) e Lambda expressions and captured variables from (Joseph Albahari).

+0

Interessante. Avrei pensato che passare un valore di tipo come argomento lo avrebbe fatto automaticamente. C'è un periodo di transizione tra la chiamata di funzione e quando viene eseguita la prima riga che potrei cambiare prima che venga copiata nella lista degli argomenti di WorkerThread? – Jakotheshadows

+0

Grazie per la risposta e le fonti. E sì, @Jakotheshadows ho assunto lo stesso – JonasMH

+0

Credo che abbia senso per me ora. La chiamata di funzione a WorkerThread non si verifica necessariamente quando si esegue thread.Start() ;. Potrebbe accadere in qualsiasi momento durante il ciclo ed è solo quando WorkerThread viene chiamato nell'altro thread (forse 5 iterazioni prima di dove è stato istanziato il thread) che io sono stato valutato e copiato nella lista degli argomenti. Il problema qui è che non mi viene valutato fino a quando il thread non inizia effettivamente. – Jakotheshadows

0

Il problema è che la variabile i si riferisce alla stessa posizione di memoria attraverso la vita del ciclo. Pertanto, ogni thread chiama una variabile il cui valore può cambiare mentre è in esecuzione. La soluzione consiste nell'utilizzare una variabile temporanea int temp = i. come ha detto @ S.Akbari.

+1

Il primo 'volatile' può essere applicato solo ai campi classe o struct, non ai locali. In secondo luogo, non cambierebbe il fatto che la variabile acquisita potrebbe essere incrementata prima dell'esecuzione del thread creato in precedenza. – juharr