如果“值类型”变量仍在被另一个线程使用(通过“ref”传递),那么在离开方法作用域时如何从堆栈中释放该变量?

1 c# memory-management .net-core

假设我们有一个method A声明变量“int Q”,启动另一个在新线程中method B接受变量Q作为参数并返回。ref int

考虑到,根据这个答案,.NET 将“堆栈中变量 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++;
    }
}
Run Code Online (Sandbox Code Playgroud)

Mar*_*ell 5

当您将变量“捕获”到 lambda 委托或异常方法中时:它会更改位置 - 它不再是堆栈变量。本质上,这是:

int crossThreadInt = 10;
// ...
var t = Task.Run(() => AsyncInfiniteMethod(ref crossThreadInt));
Run Code Online (Sandbox Code Playgroud)

变成:

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
}
Run Code Online (Sandbox Code Playgroud)

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