异步方法在当前线程(主线程)中启动AsyncCallback

时间:2017-10-16 08:12:22

标签: c# .net multithreading sockets asynchronous

有一个TcpListener类的服务器。它使用BeginAcceptTcpClient(AsyncCallback,Object)方法接受传入连接。

代码写在示例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
    }
}

问题是DoAcceptTcpClientCallback(IAsyncResult ar)方法有时在当前线程(main)中开始执行,而不是新线程,并阻塞它(main)。因此,无法接收以下连接。 请帮助理解为什么不为此方法创建一个线程

1 个答案:

答案 0 :(得分:2)

是的,正如您所发现的,you're not guaranteed that your AsyncCallback is called on a new thread。基本上,如果异步操作完成得如此之快以至于回调可以从同一个线程同步运行,那么它就会。

BeginXXX次调用希望在旧的异步模型中返回时,您正在等待发生的事情已经发生,例如在你的情况下是连接,所以为了防止不必要的上下文切换,它将IAsyncResult.CompletedSynchronously设置为true并同步执行你的回调,在你的例子中无限制地阻塞while (true)循环中的线程,永远不要让它从BeginAcceptTcpClient来电。{/ p>

您应该通过继续保持异步并快速返回,在回调方法中考虑该情况。

另外,考虑使用async/await,它们使异步编程变得更加容易。