StreamSocket.InputStreamOptions.ReadAsync在使用Wait()时卡住了。

3
这是我准备的最小可能情况:
  • 这段代码连接到imap.gmail.com
  • 读取初始服务器问候语(使用Read方法)
  • 发送NOOP命令(无操作)
  • 读取NOOP命令响应(再次使用Read方法)
问题在于第二个Read卡住了。如果使用'await ReadAsync',它可以完美地工作。
当我打断程序时,我可以看到调用堆栈从task.Wait()开始,以System.Threading.Monitor.Wait()结束。
如果我一步一步地调试这个问题,它就不会卡住。我必须承认,这看起来像是.NET框架的一个bug,但也许我错过了一些显而易见的东西。
private static async Task<byte[]> ReadAsync(StreamSocket socket)
{
    // all responses are smaller that 1024
    IBuffer buffer = new byte[1024].AsBuffer();
    await socket.InputStream.ReadAsync(
            buffer, buffer.Capacity, InputStreamOptions.Partial);
    return buffer.ToArray();
}

private static byte[] Read(StreamSocket socket)
{
    Task<byte[]> task = ReadAsync(socket);
    task.Wait();
    return task.Result;
}

private async void Button_Click(object sender, RoutedEventArgs e)
{
    Encoding encoding = Encoding.GetEncoding("Windows-1250");

    using (StreamSocket socket = new StreamSocket())
    {
        await socket.ConnectAsync(
            new HostName("imap.gmail.com"), "993", SocketProtectionLevel.Ssl);

        // notice we are using Wait() version here without any problems:
        byte[] serverGreetings = Read(socket);              

        await socket.OutputStream.WriteAsync(
            encoding.GetBytes("A0001 NOOP\r\n").AsBuffer());
        await socket.OutputStream.FlushAsync();

        //byte[] noopResponse = await ReadAsync(socket);    // works
        byte[] noopResponse = Read(socket);                 // hangs
    }
}
1个回答

4
我在我的最近一篇MSDN文章以及博客中解释了这个死锁的原因。简而言之,你不应该在异步代码中调用WaitResult;你应该始终使用await

你能解释一下为什么第一个读取块没有执行吗? - Pawel Lesnikowski
只有在任务在调用“Wait”时尚未完成时才会发生死锁(我假设 Gmail 服务器在接受连接时立即发送数据,但您必须等待命令的回复)。这也是为什么它在调试器中可以工作的原因。 - Stephen Cleary
1
是的,看起来是这样。尽管我理解为什么会死锁,但它似乎是一个错误。 - Pawel Lesnikowski
什么行为更有意义呢?实际上,唯一的选择就是改变async方法的默认行为,使其不在其上下文中恢复。但是,在这种情况下,如果您“选择加入”上下文,仍然会出现相同的死锁问题。没有办法完全避免死锁。 - Stephen Cleary

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接