首页 > 解决方案 > 为什么从管道读取会阻塞进程?

问题描述

我有两个进程(两个.NET Framework应用程序),我正在尝试使用Named Pipes 客户端连接到管道进行通信,但是当它尝试ReadAsync接收服务器发送的消息时,它开始等待 indifinetly ,即使服务器已经发送了一条消息!

令我惊讶的是,如果我关闭Server应用程序,Client 最终会继续到下一行代码(在该ReadAsync行之后),读取0个字节。

WriteAsync加载有效负载后,我必须在服务器上做些什么吗?我需要冲洗什么的吗?

服务器

static async Task Main(string[] args) {

         var server = new NamedPipeServerStream(
             "somePipe",
              PipeDirection.InOut, 
              2, 
              PipeTransmissionMode.Message
              );

         await server.WaitForConnectionAsync();

         using (StreamReader reader = new StreamReader(server)) {
              using (StreamWriter writer = new StreamWriter(server)) {

                 await writer.WriteAsync("Hello from server"); 

                 char[] buffer = new char[20];
                 var read = await reader.ReadAsync(buffer, 0, buffer.Length);
                }
         }
}

客户

 static async Task Main() {

    NamedPipeClientStream client = new NamedPipeClientStream(
             ".",
             "somePipe",
             PipeDirection.InOut,
             PipeOptions.Asynchronous);

    await client.ConnectAsync();

    try {
    using (StreamReader reader = new StreamReader(client)) {
        using (StreamWriter writer = new StreamWriter(client)) {

          var buffer = new char[20];
          int readChars = await reader.ReadAsync(buffer, 0,buffer.Length); //starts waiting indifinetly , until i close the Server

          await writer.WriteAsync("From Client");

        }
     }
     } catch (Exception ex) {

       throw;
     }
}

更新 似乎使用NamedPipeServerStream直接写入而不是StreamWriter服务器端使客户端获取数据!

服务器更改

byte[] data=Encoding.UTF8.GetBytes("Hello from server");
server.WriteAsync(data,0,data.Length);

PS 但是再次使用serverReadAsync阻塞服务器。因此将 and 包装到 and时NamedPipeServerStream会出现问题。ClientStreamStreamReaderStreamWriter

标签: .netipcnamed-pipes

解决方案


此阻塞/锁定问题是由 async/await 语法糖暗中生成的代码引起的。如果不添加ConfigureAwait(false),编译器会生成一些对 UI 应用程序来说很酷的东西(UI 是一个通用术语,可能是 ASP.NET - 不是核心 - 、WPF、Winforms 等),但否则可能是致命的。

关于这个问题已经写了很多:

不要阻塞异步代码

引:

有两种最佳做法 [...] 可以避免这种情况:

  • 在您的“库”异步方法中,尽可能使用 ConfigureAwait(false)。
  • 不要阻塞任务;一直使用异步。

并行计算 - 一切都与 SynchronizationContext 有关

为所有服务器端代码调用 ConfigureAwait 的最佳实践

我应该在每个等待的操作上调用 ConfigureAwait(false)

因此,最简单的解决方案是在您的代码中添加不知道在 UI 中运行的任何地方,或者在任何地方使用ConfigureAwait(false) async 永远不要在整个代码中阻塞任何任务,真的在任何地方,包括在您不拥有的代码中)。

恕我直言,这太荒谬了……如果我忘记在每次async通话后添加它,我个人会使用一个对我大喊大叫的 Visual Studio 扩展:-)

请注意,有一些替代方法,例如: ConfigureAwait(false) 的替代方法无处不在


推荐阅读