开发者

Why does using the Asynchronous Programming Model in .Net not lead to StackOverflow exceptions?

For example, we call BeginReceive and have the callback method that BeginReceive executes when it has completed. If that开发者_Python百科 callback method once again calls BeginReceive in my mind it would be very similar to recursion. How is that this does not cause a stackoverflow exception. Example code from MSDN:

private static void Receive(Socket client) {
    try {
        // Create the state object.
        StateObject state = new StateObject();
        state.workSocket = client;

        // Begin receiving the data from the remote device.
        client.BeginReceive( state.buffer, 0, StateObject.BufferSize, 0,
            new AsyncCallback(ReceiveCallback), state);
    } catch (Exception e) {
        Console.WriteLine(e.ToString());
    }
}

private static void ReceiveCallback( IAsyncResult ar ) {
    try {
        // Retrieve the state object and the client socket 
        // from the asynchronous state object.
        StateObject state = (StateObject) ar.AsyncState;
        Socket client = state.workSocket;

        // Read data from the remote device.
        int bytesRead = client.EndReceive(ar);

        if (bytesRead > 0) {
            // There might be more data, so store the data received so far.
        state.sb.Append(Encoding.ASCII.GetString(state.buffer,0,bytesRead));

            // Get the rest of the data.
            client.BeginReceive(state.buffer,0,StateObject.BufferSize,0,
                new AsyncCallback(ReceiveCallback), state);
        } else {
            // All the data has arrived; put it in response.
            if (state.sb.Length > 1) {
                response = state.sb.ToString();
            }
            // Signal that all bytes have been received.
            receiveDone.Set();
        }
    } catch (Exception e) {
        Console.WriteLine(e.ToString());
    }
}


BeginReceive registers a callback function associated with an overlapped IO operation. The callback will be called by the operating system when the data is available, but the BeginReceive call returns immediately, and therefore your invocation of ReceiveCallback also finishes.
Think of the actual IO as happening in a thread that doesn't belong to you, but rather to the OS. Your act of registering the callback just says "keep calling me when something happens", but it doesn't get added to the stack. That's why it is called asynchronous.


An interesting question, but after you call BeginReceive, your function continues to execute and then eventually returns, so there is no real recursion there.


Because the BeginReceive calls onto another arbitrary thread - each thread contains their own stack. Even though the same code is running, the stack never gets deep enough on a given thread to cause an exception. The stack unwinds if the call across to the other thread is non-blocking - it makes the call then continues as normal. You would get issues if they each waited, but never returned.

In your sample, depending on the code path - it could arguably run forever. The idea is similar to co-routines, where methods constantly call each other in a crude ping-pong fashion, but again no stack issues.


Using

client.BeginReceive(state.buffer,0,StateObject.BufferSize,0, 
    new AsyncCallback(ReceiveCallback), state);

does not automatically call the ReceiveCallback method, that method is called when the operation is finished.

In the meantime, the method that called the BeginReceive continues executing, doing whatever it does, and returning happily, thus removing itself from the stack.

When you use recursion, every call adds a stack frame (see comment), that is not popped until the called method returns, so the stack grows until the recursion is done.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜