C# 创建新线程时运行false if语句

C# 创建新线程时运行false if语句,c#,multithreading,C#,Multithreading,我正在编写一个程序,它将通过电子邮件向邮件列表中的任何人发送Cat事实(不是垃圾邮件,这更像是一种学习体验)。我有两个数组,一个用于事实(没有问题),一个用于电子邮件。用于电子邮件的语句总是会抛出异常(即使在try/catch块中也是如此),并且在运行该语句时,我的所有if语句都会被完全忽略 public void Broadcast() { fact++; if (fact ==factCount) { fact = 0; } String[]

我正在编写一个程序,它将通过电子邮件向邮件列表中的任何人发送Cat事实(不是垃圾邮件,这更像是一种学习体验)。我有两个数组,一个用于事实(没有问题),一个用于电子邮件。用于电子邮件的语句总是会抛出异常(即使在try/catch块中也是如此),并且在运行该语句时,我的所有if语句都会被完全忽略

public void Broadcast() {
    fact++;
    if (fact ==factCount) {
        fact = 0;
    }
    String[] mailArray = mailingList.ToArray();
    String[] factArray = factList.ToArray();
    int i = mailArray.Length-1;
    String sendFact = factArray[fact];
    while (i>=0) {
        String s = mailArray[i];
        var t = new Thread(() => Mail(mailArray[i], sendFact));
        t.IsBackground = true;
        t.Start();
        i--;
        if (i==-1) {
            break;
        }
    }
问题在于:

var t = new Thread(() => Mail(mailArray[i], sendFact));
即使“i”为-1,while语句仍会运行,中断也会被忽略。最初我反向运行“I”,从0开始,然后计数到mailArray.Length-1。它仍然给出了相同的问题,忽略了while和break,当我将它们设置为反向运行时

这是创建新线程的问题吗

编辑:

我动议:

    var t = new Thread(() => Mail(mailArray[i], sendFact));
    t.IsBackground = true;
    t.Start();

创建一个新方法,并调用它,而不是上面的代码-这工作得非常好。

您正在创建一个循环变量上的闭包-这是一个

直接使用
s
,因为您已经为其指定了当前值,可以修复它:

while (i>=0)
{
  string s = mailArray[i];
  var t = new Thread(() => Mail(s, sendFact));
  //..
}
这是创建新线程的问题吗

有点。在lambda表达式中捕获
i
,然后对其进行更改是一个问题。这意味着当线程执行lambda表达式时,它在创建线程的循环迭代中采用当前值
i
,而不是
i

最简单的解决方案是在循环内声明一个新的局部变量,将
i
复制到其中,然后在lambda表达式中使用该变量:

while (i >= 0)
{
    var copy = i;
    String s = mailArray[i];
    var t = new Thread(() => Mail(mailArray[copy], sendFact));
    t.IsBackground = true;
    t.Start();
    i--;
}
while (i >= 0)
{
    String s = mailArray[i];
    var t = new Thread(() => Mail(s, sendFact));
    t.IsBackground = true;
    t.Start();
    i--;
}
() => Mail(mailArray[i], sendFact)
int temp = i;
var t = new Thread(() => Mail(mailArray(temp), sendFact));
或者只需使用已在lambda表达式外部初始化的
s

while (i >= 0)
{
    var copy = i;
    String s = mailArray[i];
    var t = new Thread(() => Mail(mailArray[copy], sendFact));
    t.IsBackground = true;
    t.Start();
    i--;
}
while (i >= 0)
{
    String s = mailArray[i];
    var t = new Thread(() => Mail(s, sendFact));
    t.IsBackground = true;
    t.Start();
    i--;
}
() => Mail(mailArray[i], sendFact)
int temp = i;
var t = new Thread(() => Mail(mailArray(temp), sendFact));
或者,更容易理解的是,IMO,只需使用
foreach
循环:

foreach (var item in mailArray)
{
    Thread t = new Thread(() => Mail(item, sendFact)) { IsBackground = true };
    t.Start();
}
在C#3和C#4下也会出现同样的问题,但在C#5下,在
foreach
循环中捕获迭代器变量的行为是固定的


(您应该考虑使用<代码>任务>代码>而不是<代码>线程< /代码>,并且可能使用“<代码>并行”之类的东西.Furace >,BTW.

这是一个常见的问题,它与这个lambda表达式的创建有关:

while (i >= 0)
{
    var copy = i;
    String s = mailArray[i];
    var t = new Thread(() => Mail(mailArray[copy], sendFact));
    t.IsBackground = true;
    t.Start();
    i--;
}
while (i >= 0)
{
    String s = mailArray[i];
    var t = new Thread(() => Mail(s, sendFact));
    t.IsBackground = true;
    t.Start();
    i--;
}
() => Mail(mailArray[i], sendFact)
int temp = i;
var t = new Thread(() => Mail(mailArray(temp), sendFact));
基本上,您告诉thread类启动一个新线程,当它启动时,执行该代码

不幸的是,它不会对当时
i
的值进行快照,因此假设由于时间原因,在线程实际启动之前,您设法增加了
i
。线程将使用当前值
i
,而不是创建lambda时的值
i
调用该lambda

然而,这很容易解决

在while循环中,添加一个临时变量以捕获
i
的当前值,并在lambda表达式中使用该变量:

while (i >= 0)
{
    var copy = i;
    String s = mailArray[i];
    var t = new Thread(() => Mail(mailArray[copy], sendFact));
    t.IsBackground = true;
    t.Start();
    i--;
}
while (i >= 0)
{
    String s = mailArray[i];
    var t = new Thread(() => Mail(s, sendFact));
    t.IsBackground = true;
    t.Start();
    i--;
}
() => Mail(mailArray[i], sendFact)
int temp = i;
var t = new Thread(() => Mail(mailArray(temp), sendFact));

有关更多信息,请查看以下链接:。

您会遇到什么异常?lambda捕获的是
i
变量,而不是值。因此,当线程开始时,
i
-1
。相关:一般建议:使用foreach循环,不要作为初学者使用线程(很难正确)。是的,这很有效。我试着让字符串s看看它是否会抛出异常,我没有想到只用s来启动线程。