代码之家  ›  专栏  ›  技术社区  ›  Jan

写入控制台streamwriter时出现死锁

  •  1
  • Jan  · 技术社区  · 6 年前

    Eddi1: 简化问题: 如何找出当前(本机)堆栈在等待什么?:

     # Child-SP          RetAddr           Call Site
    00 000000bb`62e6de78 00007fff`e7b07489 ntdll!NtWriteFile+0x14
    01 000000bb`62e6de80 00007fff`a6bfb526 KERNELBASE!WriteFile+0x79
    02 000000bb`62e6def0 00007fff`a6b3d802 mscorlib_ni!DomainNeutralILStubClass.IL_STUB_PInvoke(System.Runtime.CompilerServices.StackCrawlMarkHandle, System.Runtime.CompilerServices.ObjectHandleOnStack)$##6000000+0x246
    03 000000bb`62e6dfd0 00007fff`a6b3d77b mscorlib_ni!System.IO.__ConsoleStream.WriteFileNative(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte[], Int32, Int32, Boolean)$##600166A+0x72
    

    (当然没有ntdll的私有符号和源:-/)

    我知道它没有进展(它试图推送到控制台的输出从未出现过,它在同一个堆栈中已经有很长时间了)。有趣的是,它显示了supsend count 0:

    0:019> ~19
    . 19  Id: 3bac.1fd8 Suspend: 0 Teb: 000000bb`6059d000 Unfrozen
          Start: clr!Thread::intermediateThreadProc (00007fff`b456cad0)
          Priority: 0  Priority class: 32  Affinity: ff
    

    原题 (以及全部内容):

    我正在调查死锁应用程序的转储,其中线程卡在以下堆栈中:

    0:019> !clrstack
    The version of SOS does not match the version of CLR you are debugging.  Please
    load the matching version of SOS for the version of CLR you are debugging.
    CLR Version: 4.7.3101.0
    SOS Version: 4.7.2563.0
    OS Thread Id: 0x1fd8 (19)
            Child SP               IP Call Site
    000000bb62e6df28 00007fffeb79a094 [InlinedCallFrame: 000000bb62e6df28] Microsoft.Win32.Win32Native.WriteFile(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte*, Int32, Int32 ByRef, IntPtr)
    000000bb62e6df28 00007fffa6bfb526 [InlinedCallFrame: 000000bb62e6df28] Microsoft.Win32.Win32Native.WriteFile(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte*, Int32, Int32 ByRef, IntPtr)
    000000bb62e6def0 00007fffa6bfb526 DomainNeutralILStubClass.IL_STUB_PInvoke(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte*, Int32, Int32 ByRef, IntPtr)
    000000bb62e6dfd0 00007fffa6b3d802 System.IO.__ConsoleStream.WriteFileNative(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte[], Int32, Int32, Boolean)
    000000bb62e6e040 00007fffa6b3d77b System.IO.__ConsoleStream.Write(Byte[], Int32, Int32)
    000000bb62e6e080 00007fffa6b3b458 System.IO.StreamWriter.Flush(Boolean, Boolean)
    000000bb62e6e0e0 00007fffa6b3d727 System.IO.StreamWriter.Write(Char[], Int32, Int32)
    000000bb62e6e140 00007fffa6b3d612 System.IO.TextWriter+SyncTextWriter.WriteLine(System.String)
    

    生成此堆栈的代码正在将文本写入先前捕获的TextWriter,如下所示:

    public static readonly TextWriter OriginalConsoleWriter = Console.Out;
    

    以前,同一应用程序域中的不同线程能够向同一streamwriter写入数据(输出在console中,从日志中我们可以看到该线程向其他函数前进)。 同一应用程序域中没有其他线程从控制台读/写 在不同的('main')应用程序域中有一个线程正在console.readline()上等待:

    Child-SP         RetAddr          Caller, Callee
    000000bb6193e7e0 00007fffe7b079c6 KERNELBASE!ReadFile+0x76, calling ntdll!NtReadFile
    000000bb6193e7f8 00007fffb4566a8f clr!SafeHandle::DangerousAddRef+0x6f, calling clr!LazyMachStateCaptureState
    000000bb6193e860 00007fffa6bfb526 (MethodDesc 00007fffa6783f60 +0xc6 DomainNeutralILStubClass.IL_STUB_PInvoke(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte*, Int32, Int32 ByRef, IntPtr))
    000000bb6193e8c8 00007fffa6bfb526 (MethodDesc 00007fffa6783f60 +0xc6 DomainNeutralILStubClass.IL_STUB_PInvoke(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte*, Int32, Int32 ByRef, IntPtr))
    000000bb6193e940 00007fffa742779a (MethodDesc 00007fffa6898440 +0xba System.IO.__ConsoleStream.ReadFileNative(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte[], Int32, Int32, Boolean, Boolean, Int32 ByRef)), calling 00007fffa6aae778 (stub for Microsoft.Win32.Win32Native.ReadFile(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte*, Int32, Int32 ByRef, IntPtr))
    000000bb6193e9d0 00007fffa74276a4 (MethodDesc 00007fffa6898420 +0x64 System.IO.__ConsoleStream.Read(Byte[], Int32, Int32)), calling (MethodDesc 00007fffa6898440 +0 System.IO.__ConsoleStream.ReadFileNative(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte[], Int32, Int32, Boolean, Boolean, Int32 ByRef))
    000000bb6193ea30 00007fffa6b98024 (MethodDesc 00007fffa676cc38 +0x44 System.IO.StreamReader.ReadBuffer())
    000000bb6193ea80 00007fffa6b985be (MethodDesc 00007fffa676cc50 +0x15e System.IO.StreamReader.ReadLine())
    000000bb6193eae0 00007fffa75dd03c (MethodDesc 00007fffa689fc50 +0x3c System.IO.TextReader+SyncTextReader.ReadLine())
    000000bb6193eb00 00007fffb4564595 clr!ThePreStub+0x55, calling clr!PreStubWorker
    000000bb6193eb40 00007fffa73c17a3 (MethodDesc 00007fffa6753220 +0x23 System.Console.ReadLine())
    

    但是,我无法从dump中的托管堆栈检测到任何死锁或阻塞,也无法!DLK命令:

    0:019> !dlk
    Examining SyncBlocks...
    Scanning for ReaderWriterLock instances...
    Scanning for holders of ReaderWriterLock locks...
    Scanning for ReaderWriterLockSlim instances...
    Scanning for holders of ReaderWriterLockSlim locks...
    Examining CriticalSections...
    No deadlocks detected.
    

    我应该在哪里/如何检查内部可能阻塞的内容 Microsoft.Win32.Win32Native.WriteFile (ntdll!NtWriteFile) 打电话?

    1 回复  |  直到 6 年前
        1
  •  0
  •   Jan    5 年前

    这很可能是由 快速编辑或标记/选择模式 控制台。 在我的机器上尝试时-闯入简单的控制台应用程序,该应用程序正在向控制台喷射,当前在选择期间被阻止-我在堆栈顶部看到:

    # Child-SP          RetAddr           Call Site
    00 00000028`48bde818 00007fff`c33a1cbc ntdll!NtWriteFile+0xa
    01 00000028`48bde820 00007fff`81c4c0c6 KERNELBASE!WriteFile+0x88
    

    这与我们事件的堆栈顶部非常相似(偏移量是位移动的;但是它是不同的操作系统-所以这是可能的;我已经无法从事件访问机器)。

    这是一个遗留应用程序,因此我们通过托管进程并将输入/输出重定向到主机进程控制台来解决这个问题,主机进程控制台已经在以适当的异步方式处理控制台交互。