启动新线程时抛出 IndexOutOfRangeException

发布于 2024-12-12 01:40:35 字数 291 浏览 0 评论 0原文

当我运行以下代码段时,会引发 IndexOutOfRangeException。看起来抛出异常时 i 是 2。我的理解是,i的值改变后,新线程就启动了。有没有办法让这段代码免受此类问题的影响?

int x[2] = {1, 3};
int numberOfThreads = 2;

for (int i = 0; i < numberOfThreads; i++)
{
    new Thread(() =>
    {
        DoWork(x[i]);
    }).Start();
}

When I run the following code piece, a IndexOutOfRangeException is thrown. It appears that i is 2 when the exception is thrown. My understanding is that the new thread is started after the value of i has been changed. Is there a way to make this code safe from this kind of problem?

int x[2] = {1, 3};
int numberOfThreads = 2;

for (int i = 0; i < numberOfThreads; i++)
{
    new Thread(() =>
    {
        DoWork(x[i]);
    }).Start();
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

唔猫 2024-12-19 01:40:35

问题是 变量 i 被捕获,当线程实际启动时,它是 2。

请改用:

for (int i = 0; i < numberOfThreads; i++)
{
    int value = x[i];
    new Thread(() => DoWork(value)).Start();
}

Or:

foreach (int value in x)
{
    int copy = value;
    new Thread(() => DoWork(copy)).Start();
}

Or:

for (int i = 0; i < numberOfThreads; i++)
{
    int copyOfI = i;
    new Thread(() => DoWork(x[copyOfI])).Start();
}

在每种情况下,lambda 表达式将在循环的每次迭代中捕获一个新变量 - 该变量不会被后续迭代更改。

一般来说,您应该避免在稍后执行的 lambda 表达式中捕获循环变量。请参阅 有关更多详细信息,请参阅 Eric Lippert 关于该主题的博客文章

从 C# 5 开始,foreach 循环行为可能会发生变化,以避免出现问题 - 但 for 循环等效项仍然是一个问题。

The problem is that the variable i is being captured, and by the time the thread actually gets to start, it's 2.

Use this instead:

for (int i = 0; i < numberOfThreads; i++)
{
    int value = x[i];
    new Thread(() => DoWork(value)).Start();
}

Or:

foreach (int value in x)
{
    int copy = value;
    new Thread(() => DoWork(copy)).Start();
}

Or:

for (int i = 0; i < numberOfThreads; i++)
{
    int copyOfI = i;
    new Thread(() => DoWork(x[copyOfI])).Start();
}

In each case, the lambda expression will capture a new variable on each iteration of the loop - a variable which won't be changed by subsequent iterations.

In general, you should avoid capturing the loop variable in a lambda expression which will be executed later. See Eric Lippert's blog post on the topic for more details.

As of C# 5, it's likely that the foreach loop behaviour will be changed to avoid this being a problem - but the for loop equivalent would still be an issue.

千纸鹤 2024-12-19 01:40:35

您正在关闭循环变量,为了获取 i当前值,请使用本地副本:

for (int i = 0; i < numberOfThreads; i++)
{
    int localI = i;
    new Thread(() =>
    {
        DoWork(x[localI]);
    }).Start();
}

You are closing over the loop variable, to get the current value of i use a local copy instead:

for (int i = 0; i < numberOfThreads; i++)
{
    int localI = i;
    new Thread(() =>
    {
        DoWork(x[localI]);
    }).Start();
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文