2010-04-30 6 views
3

Je reçois un comportement étrange ... quand j'itérer sur la dummyTextList dans la méthode ThreadTest je reçois un index hors d'exception de la plage (ArgumentOutOfRangeException), mais si je retire la threads et je viens d'imprimer le texte, alors tout fonctionne bien.Pour l'index de boucle hors de portée ArgumentOutOfRangeException quand multithreading

Ceci est ma méthode principale:

public static Object sync = new Object(); 
static void Main(string[] args) 
{ 
    ThreadTest(); 
    Console.WriteLine("Press any key to continue."); 
    Console.ReadKey(); 
} 

Cette méthode lance l'exception:

private static void ThreadTest() 
{ 
    Console.WriteLine("Running ThreadTest"); 
    Console.WriteLine("Running ThreadTest"); 
    List<String> dummyText = new List<string>() 
    { "One", "Two", "Three", "Four", "Five", 
     "Six", "Seven", "Eight", "Nine", "Ten"}; 

    for (int i = 0; i < dummyText.Count; i++) 
    { 
     Thread t = new Thread(() => PrintThreadName(dummyText[i])); // <-- Index out of range?!? 
     t.Name = ("Thread " + (i)); 
     t.IsBackground = true; 
     t.Start(); 
    } 
} 

private static void PrintThreadName(String text) 
{ 
    Random rand = new Random(DateTime.Now.Millisecond); 
    while (true) 
    { 
     lock (sync) 
     { 
      Console.WriteLine(Thread.CurrentThread.Name + " running " + text); 
      Thread.Sleep(1000+rand.Next(0,2000)); 
     } 
    } 
} 

Cela ne jette pas l'exception:

private static void ThreadTest() 
{ 
    Console.WriteLine("Running ThreadTest"); 
    List<String> dummyText = new List<string>() 
    { "One", "Two", "Three", "Four", "Five", 
     "Six", "Seven", "Eight", "Nine", "Ten"}; 

    for (int i = 0; i < dummyText.Count; i++) 
    { 
     Console.WriteLine(dummyText[i]); // <-- No exception here 
    } 
} 

Quelqu'un sait-il pourquoi est-ce événement?

Répondre

13

Lorsque vous passez une variable locale dans un thread ou un délégué ThreadPool via une fermeture, vous devez effectuer une copie de la variable. Comme dans:

for (int i = 0; i < dummyText.Count; i++) 
{ 
    int index = i; 
    Thread t = new Thread(() => PrintThreadName(dummyText[index])); 
    // ... 
} 

Si vous ne le faites pas, alors la variable se fond transmise par référence, et l'indice dépasse les limites du tableau à la fin de la boucle for (qui peut se produire bien avant que la fermeture soit jamais exécutée).

+2

La copie ne devrait-elle pas être effectuée en dehors de l'expression lambda, puisque l'expression lambda n'est pas invoquée avant que le thread ne démarre réellement? –

+0

@Michael OUI! C'était ça ... juste essayé et ça a marché. – Kiril

+0

@Michael: Wow, je dois être fatigué, je n'écrirais jamais ça! Merci pour la prise rapide. – Aaronaught