假设我们有一个method A
声明变量'int Q',启动另一个method B
,接受变量Q
作为新线程中的ref int
参数并返回。
考虑到,根据这个答案,.NET在stack中传递变量Q的地址。当通过引用传递到method B
时-当控制离开method A
的范围时,运行时不应该清除该方法内分配的变量堆栈吗?这是否意味着如果原始线程继续运行(并在堆栈上分配其他变量),method B
可能会损坏这些变量中的一个,因为"地址";它指的是不属于变量Q
了吗?
我肯定理解错了,因为当我运行下面的代码片段时,我没有注意到manyInts
数组有任何变化。
public static void Main(string[] args)
{
Outer();
int[] manyInts = new int[100000];
Thread.Sleep(5000);
}
private static void Outer()
{
int crossThreadInt = 10;
try
{
var t = Task.Run(() => AsyncInfiniteMethod(ref crossThreadInt));
t.Wait(2000);
}
catch (Exception)
{
// ignored
}
finally
{
Console.WriteLine(crossThreadInt);
}
}
private static void AsyncInfiniteMethod(ref int number)
{
while (true)
{
Thread.Sleep(100);
number++;
}
}
当你"将变量放入lambda委托或匿名方法:它改变了位置-它不再是堆栈变量。本质上,这个:
int crossThreadInt = 10;
// ...
var t = Task.Run(() => AsyncInfiniteMethod(ref crossThreadInt));
就变成:
var captureContext = new SomeCompilerGeneratedClass();
captureContext.crossThreadInt = 10;
// ...
var t = Task.Run(captureContext.SomeCompilerGeneratedMethod);
class SomeCompilerGeneratedClass {
public int crossThreadInt;
public void SomeCompilerGeneratedMethod() {
AsyncInfiniteMethod(ref this.crossThreadInt)
}
// etc
}
所以:这个问题不存在:整数从来不是堆栈局部变量;它是类上的一个字段。捕获上下文对象(拥有生存期)保持活动状态,因为它是"目标"。委托的实例。