避免c#中的递归事件

时间:2013-09-28 06:11:58

标签: c# recursion

嗨,我有点问题, 我正在使用套接字,我发现很多无限递归的情况见源:http://pastebin.com/Cbd2Z2uE

问题是:

private static void ReceiveCallback(IAsyncResult ar)
{
    ....
    // receive again
    socket.BeginReceive(state.Buffer,
        0,
        StateObject.BufferSize,
        0,
        ReceiveCallback,
    state);

    ....
}

所以我们有一个以递归方式再次调用的异步函数。这里我们有堆栈的问题? 为了更清楚,这种情况还可以,递归很好,问题和问题是: 在这种情况下,我可以遇到stackoverflow的问题吗?

感谢

2 个答案:

答案 0 :(得分:3)

您没有递归(或处于危险或递归状态)。您只是安排在IO竞争端口接收数据供您处理时执行的回调(检查源代码以查看此信息)。当您的函数在当前线程上运行时,这不会发生,因为同一个线程必须通过轮询检查IO端口上的消息,否则另一个工作线程将一起运行您的函数。在任何一种情况下,你都没有递归或有重复使用的危险,因此堆栈不会爆炸(socket.BeginReceive应立即返回并且不会调用你的函数。)

我相信您正在查看scenario 14 shown on this page,但可能是之前的情况,因为您的控制台应用有一个消息泵。但最重要的是,在您的应用程序中没有实际的函数递归(或者支持它使用的OS框架功能)。

答案 1 :(得分:2)

除非您直接调用,否则框架代码会调用ReceiveCallbackBeginReceive将指定的委托存储为回调函数,并且当时不调用委托。

例如,我添加了一些代码来获取堆栈跟踪:

private static void ReceiveCallback(IAsyncResult ar)
{
    Console.WriteLine(Environment.StackTrace);
    // retrieve the state and socket

并得到:

at System.Environment.GetStackTrace(Exception e, Boolean needFileInfo)
at System.Environment.get_StackTrace()
at Program.ReceiveCallback(IAsyncResult ar) in r:\Temp\LINQPad\aqwfvqfb\query_ettlka.cs:line 102
at System.Net.LazyAsyncResult.Complete(IntPtr userToken)
at System.Net.ContextAwareResult.CompleteCallback(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Net.ContextAwareResult.Complete(IntPtr userToken)
at System.Net.LazyAsyncResult.ProtectedInvokeCallback(Object result, IntPtr userToken)
at System.Net.Sockets.BaseOverlappedAsyncResult.CompletionPortCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped)
at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)

即使您在BeginReceive中拨打ReceiveCallback,也会显示。