【问题标题】:AnonymousPipeServerStream.Read() occasionally hangs on client exitAnonymousPipeServerStream.Read() 偶尔会在客户端退出时挂起
【发布时间】:2012-01-27 13:51:43
【问题描述】:

我有一个主程序和一个从属程序,它们通过一对匿名管道进行交互。

交互如下所示:

  • Master 创建两个 AnonymousPipeServerStream
  • Master 启动客户端进程,给他他们的 .GetClientHandleAsString()
  • Master .DisposeLocalCopyOfClientHandle 的两个管道
  • Master 将内容写入一个管道并从另一个管道读取内容
  • 有时 master 会从另一个线程 (Process.Kill()) 强行终止 slave,并且还会关闭两个管道对象。

在极少数情况下,在从属设备终止时,从主设备一侧的管道读取会无限期地阻塞 - 或者有时肯定会(例如几分钟)。我无法在我的本地机器上重现它,但它有时会在大型集群上发生。

我捕获了这种情况的转储,这就是我所看到的:

阻塞主机的堆栈跟踪(我 100% 确定此时客户端进程已经终止):

000000000c83e488 000000007700fdba [NDirectMethodFrameStandalone: 000000000c83e488] Microsoft.Win32.UnsafeNativeMethods.ReadFile(Microsoft.Win32.SafeHandles.SafePipeHandle, Byte*, Int32, Int32 ByRef, IntPtr)
000000000c83e430 000007feeab32820 DomainBoundILStubClass.IL_STUB_PInvoke(Microsoft.Win32.SafeHandles.SafePipeHandle, Byte*, Int32, Int32 ByRef, IntPtr)*** WARNING: Unable to verify checksum for System.Core.ni.dll

000000000c83e540 000007feeac14574 System.IO.Pipes.PipeStream.ReadFileNative(Microsoft.Win32.SafeHandles.SafePipeHandle, Byte[], Int32, Int32, System.Threading.NativeOverlapped*, Int32 ByRef)
000000000c83e5a0 000007feeac14a23 System.IO.Pipes.PipeStream.ReadCore(Byte[], Int32, Int32)
000000000c83e610 000007fef0169d8f System.IO.BinaryReader.FillBuffer(Int32)
000000000c83e650 000007fef0169c8a System.IO.BinaryReader.ReadInt32()

我还查看了阻塞的 AnonymousPipeServerStream 对象,以及它的状态和句柄。

它有:

  • m_state = 4(即关闭)
  • m_clientHandle 是一个关闭的句柄(根据 SafeHandle._state 和 !handle 的输出)
  • m_handle 是一个打开的句柄,_state = 6(即未关闭,即使 Pipe 对象已关闭,根据反编译,它应该调用 m_handle.Dispose()):

这是主端句柄的 !handle 的输出。

0:000> !handle 1850 ff
Handle 0000000000001850
  Type          File
  Attributes    0
  GrantedAccess 0x120189:
         ReadControl,Synch
         Read/List,ReadEA,ReadAttr,WriteAttr
  HandleCount   2
  PointerCount  5
  No object specific information available

我有点担心 HandleCount 是 2 而 PointerCount 是 5。

有什么可能出错的想法吗?为什么我关闭管道时读取手柄的主端没有关闭?尽管客户端终止并且尽管我调用了 DisposeLocalCopyOfClientHandle,但为什么管道没有损坏?

我至少可以做些什么来解决这个问题?也许只是在阅读线程上做 Thread.Interrupt ?..

【问题讨论】:

  • 如何启动子进程? bInheritHandles 参数的值是多少?
  • 我没有明确指出。但我确实将管道句柄标记为可继承(在 AnonymousPipeServerStream 的构造函数中)
  • 由于依赖最终是在管道上,您是否可以让需要通过关闭所述管道触发的事件来释放管道的线程?只是一个想法。
  • @jkff 这是一个有趣的问题。你找到解决办法了吗?
  • @arx 不幸的是没有 - 解决方案是将我的程序回滚到使用标准输入/标准输出传输。 Thread.Interrupt 在这里不起作用,顺便说一句。

标签: c# .net windows debugging pipe


【解决方案1】:

主进程中可能的事件序列,前面是线程号:

  • 1 - 即将调用 Microsoft.Win32.UnsafeNativeMethods.ReadFile(在 BinaryReader.ReadInt32 内)
  • 2 - 杀死从属进程并关闭管道句柄
  • 3 - win32 管道句柄(现在已关闭)被其他管道(或文件或其他任何东西)重用
  • 1 - Microsoft.Win32.UnsafeNativeMethods.ReadFile 使用现在引用其他对象的旧句柄开始读取,并阻塞。

修复:

杀死线程 2 中的从属进程,但不要关闭句柄。这将导致线程 1 中的任何读取终止,然后关闭线程 1 中的管道句柄。

道德:

在您仍在使用句柄时不要关闭它们。

【讨论】:

    猜你喜欢
    • 2016-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-24
    相关资源
    最近更新 更多