【发布时间】:2018-04-17 09:05:47
【问题描述】:
我试图在程序的某个部分可靠地跟踪我的堆栈高度,以便自适应地调整机器学习算法。
现在,我的代码如下所示:
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);
}
我知道将Interlocked 与ThreadStatic 字段一起使用不是必需的,并且我知道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 参数。
如果不可能,我可以采用两种选择之一。
- 在堆栈上传递堆栈的高度(例如,将其作为方法参数传递)。这显着增加了我的代码库中许多方法的复杂性。
- 在根调用站点,在调用递归部分之前和之后将
stackHeight设置为0(即使在出现异常的情况下)。这感觉……很糟糕。
那么, 对我的用例来说可能有类似的可能性,还是我需要求助于其他方法?
编辑:
最佳猜测:
var incremented = false;
try
{
RuntimeHelpers.PrepareConstrainedRegions();
try
{
}
finally
{
stackHeight++;
incremented = true;
}
// Use `stackHeight`
}
finally
{
if (incremented)
{
stackHeight--;
}
}
【问题讨论】:
标签: c# .net multithreading recursion stack-overflow