【问题标题】:Why would fclose hang / deadlock? (Windows)为什么 fclose 会挂起/死锁? (视窗)
【发布时间】:2011-08-31 07:57:38
【问题描述】:

我有一个目录更改监视器进程,它从一组目录中的文件中读取更新。我有另一个进程对这些目录(测试程序)的大量文件执行小写操作。大概有 100 个目录,每个目录有 10 个文件,每秒大约有 500 个文件被修改。

运行一段时间后,目录监视器进程挂起对fclose() 的调用,该方法基本上是拖尾文件。在这个方法中,我 fopen() 文件,检查句柄是否有效,进行几次查找和读取,然后调用 fclose()。这些读取都是由进程中的同一个线程执行的。挂起后,线程永远不会继续。

我找不到任何关于为什么fclose() 可能会死锁而不是返回某种错误代码的好信息。该文档确实提到了_fclose_nolock(),但我似乎无法使用它(Visual Studio 2003)。

调试和发布版本都会出现挂起。在调试版本中,我可以看到fclose() 调用_free_base(),它在返回之前挂起。对 kernel32.dll => ntdll.dll => KernelBase.dll => ntdll.dll 的某种调用正在旋转。这是 ntdll.dll 中无限循环的程序集:

77CEB83F  cmp         dword ptr [edi+4Ch],0 
77CEB843  lea         esi,[ebx-8] 
77CEB846  je          77CEB85E 
77CEB848  mov         eax,dword ptr [edi+50h] 
77CEB84B  xor         dword ptr [esi],eax 
77CEB84D  mov         al,byte ptr [esi+2] 
77CEB850  xor         al,byte ptr [esi+1] 
77CEB853  xor         al,byte ptr [esi] 
77CEB855  cmp         byte ptr [esi+3],al 
77CEB858  jne         77D19A0B 
77CEB85E  mov         eax,200h 
77CEB863  cmp         word ptr [esi],ax 
77CEB866  ja          77CEB815 
77CEB868  cmp         dword ptr [edi+4Ch],0 
77CEB86C  je          77CEB87E 
77CEB86E  mov         al,byte ptr [esi+2] 
77CEB871  xor         al,byte ptr [esi+1] 
77CEB874  xor         al,byte ptr [esi] 
77CEB876  mov         byte ptr [esi+3],al 
77CEB879  mov         eax,dword ptr [edi+50h] 
77CEB87C  xor         dword ptr [esi],eax 
77CEB87E  mov         ebx,dword ptr [ebx+4] 
77CEB881  lea         eax,[edi+0C4h] 
77CEB887  cmp         ebx,eax 
77CEB889  jne         77CEB83F 

您有什么想法吗?

【问题讨论】:

  • 我的钱被堆坏了。看看stackoverflow.com/questions/1010106/…
  • 你能把你监控过程的源代码的相关部分贴出来吗?
  • 你在fopen中使用了哪些参数?你用的是什么文件系统?哪个操作系统版本?哪个运行时库 (MT/ST)?是否涉及 DCOM(公寓模型)?
  • @Jens:以“rb”开头。文件系统是 NTFS,远程共享。进程在 Windows 7 上运行。运行时库是 MD / MDd。不涉及 DCOM。
  • @aix:抱歉,我无法发布代码。堆损坏听起来确实有可能。我会调查的。

标签: c++ windows deadlock fclose


【解决方案1】:

我也遇到过文件关闭功能的情况。就我而言,我通过定位嵌入其他函数体而不是拥有自己的函数的关闭函数来解决。

我也怀疑 (1)被复制的文件名(2)Windows调度(文件IO在下一个任务启动之前没有完成。Windows调度和多线程在幕后,所以很难验证,但我有当我尝试在循环中以 ASCII 格式保存许多数据时,类似的问题。在这种情况下解决了二进制保存问题。)

我的环境,IDE:Visual Studio 2015,操作系统:Windows 7,语言:C++

【讨论】:

    【解决方案2】:

    我将此作为评论发布,但我意识到这本身可能是一个答案......

    根据反汇编,我猜你已经覆盖了ntdll 维护的一些内部堆结构,并且它一直循环遍历链表。

    特别是在循环开始时,当前列表节点似乎在ebx 中。在循环结束时,预期的最后一个节点(或终止符,如果你喜欢 - 它看起来有点像这些循环列表,最后一个节点与第一个节点相同,指向该节点的指针位于 [edi+4Ch])包含在eax 中。 cmp ebx, eax 的结果可能永远不会相等,因为堆损坏导致列表中存在一些循环。

    我认为这与锁无关,否则我们会看到一些原子指令(例如lock cmpxchgxchg 等)或调用其他同步函数。

    【讨论】:

    • 这确实是一个堆损坏问题。 aix 几乎立即指出了这一点,但我会将其标记为实际跟踪反汇编的答案。
    猜你喜欢
    • 2012-04-19
    • 1970-01-01
    • 2015-03-09
    • 2019-12-27
    • 2019-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多