如何在回调中重用回调时防止StackOverflowException?

时间:2015-03-18 15:01:11

标签: c# asp.net .net recursion

我有一些依赖于HttpContext.Cache的代码,如果满足某个条件,我希望它重新缓存一些东西。然而,这引入了潜在的堆栈溢出,我不确定这里适当的方法是什么。

请看这段代码:

void OnCacheItemRemoved( string key, object value, CacheItemRemovedReason reason )
    {
        var c = value as RequestCounter;
        if ( c == null )
            return;

        if ( .. Some logic that might be true .. )
        {
            Cache.Insert( key, c, null, DateTime.UtcNow.AddSeconds( timeWindow ),
                Cache.NoSlidingExpiration, CacheItemPriority.Low, OnCacheItemRemoved );
        }
    }

调试时,堆栈跟踪似乎没有建立起来,但在现实生活中,确实如此。这可能取决于如何调用回调(例如,如果由于某种原因立即释放缓存)?

此外,围绕此问题的最佳解决方案是什么?传入一个带有重复代码的委托(可能将除Cache.Insert之外的逻辑移到一个常用方法)?我仍然担心它会建立一个堆栈,我不知道我有什么选择。

有什么建议吗?

1 个答案:

答案 0 :(得分:0)

根据我的观察结果添加答案:

在这种情况下防止StackOverflowException的一种解决方案

    void OnCacheItemRemoved( string key, object value, CacheItemRemovedReason reason )
    {

        if ( reason != CacheItemRemovedReason.Expired )
        {
            return;
        }

至少,这可以防止堆栈溢出。 stackoverflow异常原因背后的理论似乎是在替换缓存项(或由插入重新缓存)时调用回调。尝试缓存同一项的两个并行请求将创建一个竞争条件,其中第一个缓存项将被第二个请求过期,从而调用回调,而回调又会再次插入,调用第二个回调并生成在理性的无限失效"删除"。似乎该种族会构建调用堆栈,而过期线程则不会。