为什么会挂起/死锁?(视窗)

Haw*_*Bin 8 c++ windows deadlock fclose

我有一个目录更改监视器进程,它从一组目录中的文件读取更新.我有另一个进程,对这些目录(测试程序)执行大量文件的小写操作.图大约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 
Run Code Online (Sandbox Code Playgroud)

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

asv*_*kau 3

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

根据反汇编,我的猜​​测是您已经覆盖了由 维护的一些内部堆结构ntdll,并且它通过链表永远循环迭代。

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

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