Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 832
Mihail Avatar asked Oct 16 '17 08:10

Mihail


1 Answers

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.

like image 53
Saeb Amini Avatar answered Oct 23 '22 23:10

Saeb Amini