【问题标题】:For loop index out of range ArgumentOutOfRangeException when multithreading多线程时for循环索引超出范围ArgumentOutOfRangeException
【发布时间】:2011-02-14 01:45:45
【问题描述】:

我遇到了一些奇怪的行为...当我在 ThreadTest 方法中迭代 dummyText List 时,我得到一个索引超出范围异常 (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
    }
}

有人知道为什么会这样吗?

【问题讨论】:

    标签: c# multithreading exception lambda for-loop


    【解决方案1】:

    当您将局部变量传递给线程或ThreadPool 通过闭包委托时,您需要制作该变量的副本。如:

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

    如果你不这样做,那么变量基本上是通过引用传入的,并且索引将在for 循环的最后超出数组的边界(这可能在关闭之前很久就发生了曾经执行过)。

    【讨论】:

    • 不应该在 lambda 表达式之外进行复制,因为在线程实际启动之前不会调用 lambda 表达式?
    • @Michael:哇,我一定是累了,我永远不会写那个!感谢您的快速捕捉。
    • 你为我节省了很多时间和头痛。几天来我一直在努力解决这个问题。 +1
    猜你喜欢
    • 2019-04-17
    • 2013-11-25
    • 2017-08-09
    • 1970-01-01
    • 1970-01-01
    • 2021-09-02
    • 2020-07-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多