【问题标题】:Why would a process hang within RtlExitUserProcess/LdrpDrainWorkQueue?为什么进程会在 RtlExitUserProcess/LdrpDrainWorkQueue 中挂起?
【发布时间】:2018-10-04 14:39:47
【问题描述】:

为了调试锁定的文件问题,我们从 .NET 进程调用 SysInternal 的 Handle64.exe 4.11(通过带有异步输出重定向的 Process.Start)。调用进程挂起Process.WaitForExit,因为 Handle64 进程没有退出(超过两个小时)。

我们转储了相应的 Handle64 进程,并在 Visual Studio 2017 调试器中对其进行了检查。它显示了两个线程(“主线程”和“ntdll.dll!TppWorkerThread”)。

主线程的调用栈:

ntdll.dll!NtWaitForSingleObject ()  Unknown
ntdll.dll!LdrpDrainWorkQueue()  Unknown
ntdll.dll!RtlExitUserProcess()  Unknown
kernel32.dll!ExitProcessImplementation  ()  Unknown
handle64.exe!000000014000664c() Unknown
handle64.exe!00000001400082a5() Unknown
kernel32.dll!BaseThreadInitThunk    ()  Unknown
ntdll.dll!RtlUserThreadStart    ()  Unknown

工作线程的调用栈:

ntdll.dll!NtWaitForSingleObject()   Unknown
ntdll.dll!LdrpDrainWorkQueue()  Unknown
ntdll.dll!LdrpInitializeThread()    Unknown
ntdll.dll!_LdrpInitialize() Unknown
ntdll.dll!LdrInitializeThunk()  Unknown

我的问题是:为什么进程会在LdrpDrainWorkQueue 中挂起?从https://stackoverflow.com/a/42789684/62838,我了解到这是正在工作的 Windows 10 并行加载程序,但为什么它会在退出进程时卡住?这可能是由于我们如何从另一个进程调用 Handle64 造成的吗?即,我们是做错了什么还是这只是 Handle64 中的一个错误?

【问题讨论】:

  • 这只是 handle64 中的 1 个工作线程吗?我想更多和不同的调用堆栈。这个挂起是总是在你的系统上还是随机的?
  • 我什至可以说这是不是LoaderWorker线程的调用栈——它从不从LdrpInitializeThread调用LdrpDrainWorkQueue,因为这个线程有特殊的、非常轻的初始化
  • 我能说什么 - 在调用 ExitProcess 时 - 一些 DLL 被加载到另一个线程中,工作线程的调用堆栈 - 这 100% 不是加载器工作线程,但其他一些。主线程和这个仅开始执行的新线程(在非常早期的阶段)都在等待LdrpLoadCompleteEvent 事件。当某些 DLL 的加载完成时,此事件设置在单个位置 LdrpDropLastInProgressCount。必须是正在处理的附加胎面。这里需要更多地查看调试器。作为旁注,很容易根本不使用handle64,而是自己获取所有信息
  • @RbMm 非常感谢您的分析!根据调试器的说法,在进行转储时,Handle64.exe 中只有一个工作线程。 (可能其他线程已经退出了?)
  • 它并不总是发生,到目前为止,我们在几十个电话中只看到过一次。

标签: c++ windows multithreading process


【解决方案1】:

你等了多久?

根据this analysis

工作线程空闲超时设置为 30 秒。程序 在不到 30 秒内执行将出现挂起,因为 ntdll!TppWorkerThread 等待进程前的空闲超时 终止。

我建议尝试设置该文章中指定的注册表项以禁用并行加载程序,看看这是否解决了问题。

Parent Key: HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\handle64.exe
Value Name: MaxLoaderThreads
Type: DWORD
Value: 1 to disable

【讨论】:

  • 我们等了2个多小时,我会相应地更新问题。
  • 我们目前无法可靠地重现此问题(到目前为止,它仅在几百次调用中出现过一次),因此禁用并行加载以查看它是否可以解决问题很困难。
  • 如果没有简单的可重复性,我很想给您的WaitForExit 添加一个超时,然后放弃该过程并再次尝试运行它。我认为您不太可能在 SO 上找到能够帮助您修复它的任何人。祝你好运!
  • 在不到 30 秒内执行的程序会出现挂起这当然不是真的。工作线程自行运行 - 不会导致挂起。它不包含任何“关键部分”(广义上)。如果简单地退出线程而不调用ExitProcess 进程当然不会退出,直到该工作线程不退出,但这并没有挂起。如果我们调用ExitProcess - 我们正常退出
  • @DarkFalcon “我很想给你的 WaitForExit 添加一个超时时间”——这正是我们所做的——这个问题主要是为了更好地理解问题。 :)
猜你喜欢
  • 2011-05-17
  • 2018-10-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-09
  • 2012-02-17
  • 1970-01-01
相关资源
最近更新 更多