嗨,我有点问题, 我正在使用套接字,我发现很多无限递归的情况见源:http://pastebin.com/Cbd2Z2uE
问题是:
private static void ReceiveCallback(IAsyncResult ar)
{
....
// receive again
socket.BeginReceive(state.Buffer,
0,
StateObject.BufferSize,
0,
ReceiveCallback,
state);
....
}
所以我们有一个以递归方式再次调用的异步函数。这里我们有堆栈的问题? 为了更清楚,这种情况还可以,递归很好,问题和问题是: 在这种情况下,我可以遇到stackoverflow的问题吗?
感谢
答案 0 :(得分:3)
您没有递归(或处于危险或递归状态)。您只是安排在IO竞争端口接收数据供您处理时执行的回调(检查源代码以查看此信息)。当您的函数在当前线程上运行时,这不会发生,因为同一个线程必须通过轮询检查IO端口上的消息,否则另一个工作线程将一起运行您的函数。在任何一种情况下,你都没有递归或有重复使用的危险,因此堆栈不会爆炸(socket.BeginReceive
应立即返回并且不会调用你的函数。)
我相信您正在查看scenario 14 shown on this page,但可能是之前的情况,因为您的控制台应用有一个消息泵。但最重要的是,在您的应用程序中没有实际的函数递归(或者支持它使用的OS框架功能)。
答案 1 :(得分:2)
除非您直接调用,否则框架代码会调用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)
即使您在BeginReceive
中拨打ReceiveCallback
,也会显示。