Для индекса цикла вне диапазона ArgumentOutOfRangeException при многопоточности - PullRequest
3 голосов
/ 30 апреля 2010

У меня странное поведение ... когда я перебираю dummyText List в методе ThreadTest, я получаю индекс вне диапазона исключений (ArgumentOutOfRangeException), но если я удаляю потоки и я просто распечатываю текст, тогда все работает нормально.

Это мой основной метод:

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

Этот метод выдает исключение:

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));
        }
    }
}

Это не исключение:

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
    }
}

Кто-нибудь знает, почему это происходит?

1 Ответ

13 голосов
/ 30 апреля 2010

Когда вы передаете локальную переменную в поток или ThreadPool делегируете через замыкание, вам нужно сделать копию переменной. Как в:

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

Если вы этого не сделаете, то переменная в основном будет передана по ссылке, и индекс превысит границы массива в самом конце цикла for (что может произойти задолго до закрытия когда-либо казненный).

...