2013-05-30 16 views
2

我有这段代码给了我一个“索引在数组边界之外”。我不知道为什么会发生这种情况,因为变量i应该总是小于数组bla的长度,因此不会导致此错误。索引在尝试启动多个线程时超出了数组的范围

private void buttonDoSomething_Click(object sender, EventArgs e) 
{ 
    List<Thread> t = new List<Thread>(); 

    string[] bla = textBoxBla.Lines; 

    for (int i = 0; i < bla.Length; i++) 
    { 
     t.Add(new Thread (() => some_thread_funmction(bla[i]))); 
     t[i].Start(); 
    } 
} 

有人能告诉我如何解决这个问题,为什么会发生这种情况。谢谢!

+0

bla的内容是什么? – Maciej

+1

您需要复制'i'并将副本传递给线程函数。 –

回答

9

Closures是你的问题在这里。

基本上,不是在创建lambda时(在循环中)抓取值,而是在需要时抓取它。计算机速度非常快,在发生的时候,它已经没有了循环。和值的3 下面是一个例子(不运行它尚未):

private void buttonDoSomething_Click(object sender, EventArgs e) 
{ 
    List<Thread> t = new List<Thread>(); 
    for (int i = 0; i < 3; i++) 
    { 
     t.Add(new Thread (() => Console.Write(i))); 
     t[i].Start(); 
    } 
} 

想想你所期望的结果是什么。你在想这是否是012

现在运行它。

结果将会是333

这里的一些修改代码,会解决它:

private void buttonDoSomething_Click(object sender, EventArgs e) 
{ 
    List<Thread> t = new List<Thread>(); 
    string[] bla = textBoxBla.Lines; 
    for (int i = 0; i < bla.Length; i++) 
    { 
     int y = i; 
     //note the line above, that's where I make the int that the lambda has to grab 
     t.Add(new Thread (() => some_thread_funmction(bla[y]))); 
     //note that I don't use i there, I use y. 
     t[i].Start(); 
    } 
} 

现在,它会正常工作。这次该值在循环结束时超出范围,所以lambda别无选择,只能在循环结束之前将其取出。这会让你的预期结果,并没有例外。

+0

谢谢,它现在可行!我会在几分钟内将您的答案设置为最佳状态。 – armin

2

你所看到的是一种竞赛条件。您的for循环在线程实际启动之前完成。所以当线程实际开始的时候i的值超出了数组的范围。

尝试复制索引值并传入副本。

private void buttonDoSomething_Click(object sender, EventArgs e) 
{ 
    List<Thread> t = new List<Thread>(); 

    string[] bla = textBoxBla.Lines; 

    for (int i = 0; i < bla.Length; i++) 
    { 
     int index = i; 
     t.Add(new Thread (() => some_thread_funmction(bla[index]))); 
     t[i].Start(); 
    } 
} 
+0

感谢您的回应:) – armin