Mihail
Mihail

Reputation: 475

The asynchronous method starts AsyncCallback in the current thread (main thread)

There is a server of TcpListener class. It accepts incoming connections using the BeginAcceptTcpClient (AsyncCallback, Object) method.

The code is written in the example MSDN

public static ManualResetEvent tcpClientConnected = 
    new ManualResetEvent(false);

public static void DoBeginAcceptTcpClient(TcpListener 
    listener)
{
    while(true)
    {
        tcpClientConnected.Reset();
        Console.WriteLine("Waiting for a connection...");
        listener.BeginAcceptTcpClient(
            new AsyncCallback(DoAcceptTcpClientCallback), 
            listener);
        tcpClientConnected.WaitOne();
    }
}
public static void DoAcceptTcpClientCallback(IAsyncResult ar) 
{
    TcpListener listener = (TcpListener) ar.AsyncState;
    TcpClient client = listener.EndAcceptTcpClient(ar);
    Console.WriteLine("Client connected completed");
    tcpClientConnected.Set();
    while(true)
    {
         //Receiving messages from the client
    }
}

The problem is that the DoAcceptTcpClientCallback (IAsyncResult ar) method sometimes starts executing in the current thread (main), not the new one, and blocks it (main). Because of this, the following connections can not be received. Please help to understand why not create a thread for this method

Upvotes: 7

Views: 1317

Answers (1)

Saeb Amini
Saeb Amini

Reputation: 24400

Yes, as you've discovered, you're not guaranteed that your AsyncCallback is called on a new thread. Basically if an asynchronous operation completes so quickly that the callback can be run synchronously from the same thread, it will.

That happens when by the time BeginXXX calls want to return in the old async model, the thing you're waiting for to happen has already happened, e.g. in your case a connection, so to prevent an unnecessary context switch, it sets IAsyncResult.CompletedSynchronously to true and executes your callback synchronously which in your example infinitely blocks the thread in the while (true) loop, never letting it return from the BeginAcceptTcpClient call.

You should account for that scenario in your callback method by continuing to remain asynchronous and returning quickly.

Also, look into using async/await, they make asynchronous programming much easier.

Upvotes: 4

Related Questions