是否可以可靠地跟踪堆栈高度/递归深度?

Is it possible to track the stack height / recursion depth reliably?

我试图在我的程序的某个部分可靠地跟踪我的堆栈高度,以便自适应地调整机器学习算法。

现在,我的代码如下所示:

private const int MaxStackHeight = 20;

[ThreadStatic]
private static int stackHeight;

...

try
{
    var currentHeight = Interlocked.Increment(ref stackHeight);
    var depthFactor = currentHeight / (double)MaxStackHeight;
    // Use `depthFactor` to limit the amount of branching & recursion at this depth by choosing simpler candidates.
}
finally
{
    Interlocked.Decrement(ref stackHeight);
}

我知道将 InterlockedThreadStatic 字段一起使用是不必要的,而且我知道 Constrained Execution Regions。但是,这个问题与 Monitor.Enter/Monitor.Exit 问题非常相似,所以我不确定使用 CER 可以解决这个问题。例如,Monitor 的解决方案是使用 .NET 4 中添加的 Monitor.TryEnter 重载之一可用的 out lockTaken 参数。Interlocked.Increment 是否有类似的策略?

Monitor (.NET 4+) 的示例解决方案:

var lockTaken = false;
try
{
    Monitor.TryEnter(handle, ref lockTaken);
}
finally
{
    if (lockTaken)
    {
        Monitor.Exit(handle);
    }
}

之所以可行,是因为 finally 块是一个受约束的执行区域,并且因为 .NET Framework 保证 out lockTaken 参数将被准确设置。

如果这不可能,我可以采用两种选择之一。

所以,我的用例可能有类似的东西,还是我需要求助于替代方法?

编辑:

最佳猜测:

        var incremented = false;
        try
        {
            RuntimeHelpers.PrepareConstrainedRegions();
            try
            {
            }
            finally
            {
                stackHeight++;
                incremented = true;
            }

            // Use `stackHeight`
        }
        finally
        {
            if (incremented)
            {
                stackHeight--;
            }
        }

我会在递归递归调用之前保留该值,并在需要时恢复它,例如:

var currentStackHeight = stackHeight;
try {
  for(var i = 0; i < 10; i++) {
    stackHeight = currentStackHeight + 1;
    recurseDeeper();
  }
}
finally {
  stackHeight = currentStackHeight;
}