简体   繁体   中英

For loop index out of range ArgumentOutOfRangeException when multithreading

I'm getting some strange behavior... when I iterate over the dummyText List in the ThreadTest method I get an index out of range exception ( ArgumentOutOfRangeException ), but if I remove the threads and I just print out the text, then everything works fine.

This is my main method:

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

This method throws the 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));
        }
    }
}

This does not throw the 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
    }
}

Does anybody know why this is happening?

When you pass a local variable into a thread or ThreadPool delegate through a closure, you need to make a copy of the variable. As in:

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

If you don't do this, then the variable basically gets passed in by reference, and the index will exceed the bounds of the array at the very end of the for loop (which may happen long before the closure is ever executed).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM