我有一个目录更改监视器进程,该进程从一组目录中的文件读取更新。我还有另一个过程,可以对这些目录(测试程序)的许多文件进行少量写入。大约有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

任何想法可能在这里发生什么?

最佳答案

我将其发布为评论,但我意识到这本身就是一个答案...

基于反汇编,我猜想您已经覆盖了ntdll维护的某些内部堆结构,并且该结构在循环遍历链表时一直循环。

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

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

关于c++ - 为什么fclose会挂起/死锁? (视窗),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/6100598/

10-11 01:11