避免在 C# 中使用递归事件

本文关键字:递归 事件 | 更新日期: 2023-09-27 18:33:11

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

问题是这样的:

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

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

谢谢

避免在 C# 中使用递归事件

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

我相信您正在查看此页面上显示的方案 14,但这可能是以前的方案,因为您的控制台应用程序具有消息泵。但最重要的是,您的应用程序中没有实际的函数递归(或它使用的辅助操作系统框架功能)。

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

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

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)
甚至

你用ReceiveCallback打电话给BeginReceive也显示.