C# 中的闭包 - 在具有值类型的函数调用中启动线程
本文关键字:类型 函数调用 线程 启动 闭包 | 更新日期: 2023-09-27 17:56:43
我有这段代码,它可以按照我想要的方式工作,但我不明白为什么。考虑到 C 中的堆栈,C++,我猜 p 变量将在每次调用时出现在堆栈上,然后在方法返回时擦除。线程的闭包如何捕获它,甚至每次捕获正确的值?输出是我想要的 - 文件是"_a"、"_b"、"_c"。
public enum enumTest
{
a = 1,
b =2,
c=3
}
private void Form1_Load(object sender, EventArgs e)
{
callme(enumTest.a);
callme(enumTest.b);
callme(enumTest.c);
}
private void callme(enumTest p)
{
Thread t = new Thread(() =>
{
Thread.Sleep(2000);
Guid guid = Guid.NewGuid();
File.WriteAllText(guid.ToString() + "_" + p.ToString(), "");
});
t.Start();
}
Lambda只是光荣的匿名代表
- 里克·斯特拉尔〔http://www.west-wind.com/weblog/posts/2008/Apr/26/Variable-Scoping-in-Anonymous-Delegates-in-C〕
Rick 的文章描述了编译器如何生成处理enumTest p
值和delegate
的类。
还有很好的信息 匿名函数体变量保存在哪里?
基本上,编译器会创建一个"闭包类"的新实例,其中包含必须传递给 lambda 的局部变量。 这就是您输出正确的原因。
更新
在以下情况下:
for (int i=0; i<10; i++)
{
var t = new Thread(() => { Console.WriteLine(i); });
t.Start();
}
变量i
在for
和lambda
之间共享。 每个线程都在访问相同的i
。 由于 for 循环倾向于在任何线程运行之前进行 finsih,因此您看到的只是"10"。
参见 http://msdn.microsoft.com/en-us/library/0yw3tz5k(v=vs.80).aspx
这与闭包无关,这里没有任何价值捕获。
这里发生的事情是,您的p
参数被按值复制到线程的函数中。每次传递给函数时,都会将新值 p
复制到函数中。
线程的闭包如何捕获它,甚至每次捕获正确的值?
这就是编译器的魔力。仅仅因为 lambda 正在使用 p
参数,编译器会以不同的方式对待它。 p
不是放在堆栈上,而是放在堆上。这就是为什么它在callme()
终止后仍然存在的原因。