如果"value type"变量仍在由另一个线程使用(由"ref"传递),则在离开方法范围时如何从堆栈中释放该变量?



假设我们有一个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
}

所以:这个问题不存在:整数从来不是堆栈局部变量;它是类上的一个字段。捕获上下文对象(拥有生存期)保持活动状态,因为它是"目标"。委托的实例。

最新更新