在fo​​reach标识符和闭包 [英] The foreach identifier and closures

查看:140
本文介绍了在fo​​reach标识符和闭包的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在以下两个片段,是第一个安全或你必须做第二个?

In the two following snippets, is the first one safe or must you do the second one?

通过安全我的意思是保证从该线程的创建相同的循环迭代呼吁美孚方法每个线程?

By safe I mean is each thread guaranteed to call the method on the Foo from the same loop iteration in which the thread was created?

或者必须引用复制到一个新的变量本地的每次循环?

Or must you copy the reference to a new variable "local" to each iteration of the loop?

var threads = new List<Thread>();
foreach (Foo f in ListOfFoo)
{      
    Thread thread = new Thread(() => f.DoSomething());
    threads.Add(thread);
    thread.Start();
}

-

var threads = new List<Thread>();
foreach (Foo f in ListOfFoo)
{      
    Foo f2 = f;
    Thread thread = new Thread(() => f2.DoSomething());
    threads.Add(thread);
    thread.Start();
}

更新:作为乔恩斯基特的答复中指出,这并没有什么专门做与线程

Update: As pointed out in Jon Skeet's answer, this doesn't have anything specifically to do with threading.

推荐答案

编辑:这一切的变化在C#5,具有变化的变量定义在哪里(在编译器的眼睛)。从C#5开始,它们是相同的。

this all changes in C# 5, with a change to where the variable is defined (in the eyes of the compiler). From C# 5 onwards, they are the same.

第二个是安全的;首先是不

The second is safe; the first isn't.

使用的foreach ,变量声明的之外循环 - 即

With foreach, the variable is declared outside the loop - i.e.

Foo f;
while(iterator.MoveNext())
{
     f = iterator.Current;
    // do something with f
}

这意味着,仅仅有1 ˚F在封闭范围而言,和线程可能很可能会感到困惑 - 调用该方法多次在某些情况下,不在所有别人。你可以用第二个变量声明的 的内部解决这个问题的循环:

This means that there is only 1 f in terms of the closure scope, and the threads might very likely get confused - calling the method multiple times on some instances and not at all on others. You can fix this with a second variable declaration inside the loop:

foreach(Foo f in ...) {
    Foo tmp = f;
    // do something with tmp
}

这则设有一个独立的 TMP 在每个封闭的范围,所以不存在这个问题的风险。

This then has a separate tmp in each closure scope, so there is no risk of this issue.

下面是问题的一个简单证明:

Here's a simple proof of the problem:

    static void Main()
    {
        int[] data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
        foreach (int i in data)
        {
            new Thread(() => Console.WriteLine(i)).Start();
        }
        Console.ReadLine();
    }

输出(随机):

1
3
4
4
5
7
7
8
9
9

添加临时变量和它的作品:

Add a temp variable and it works:

        foreach (int i in data)
        {
            int j = i;
            new Thread(() => Console.WriteLine(j)).Start();
        }

(每个数字一次,但当然顺序没有保证的)

(each number once, but of course the order isn't guaranteed)

这篇关于在fo​​reach标识符和闭包的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆