我有一个目录更改监视器进程,它从一组目录中的文件读取更新。我有另一个进程,对这些目录(测试程序)执行大量文件的小写操作。图大约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
任何想法可能会发生在这里?
答案 0 :(得分:2)
我发布此评论作为评论,但我意识到这本身就是一个答案......
根据反汇编,我的猜测是你已经覆盖了由ntdll
维护的一些内部堆结构,它正在循环遍历链表。
特别是在循环开始时,当前列表节点似乎在ebx
中。在循环结束时,预期的最后一个节点(或终止符,如果你愿意 - 它看起来有点像圆形列表,最后一个节点与第一个节点相同,指向此节点的指针位于{{1} } {}包含在[edi+4Ch]
中。可能eax
的结果永远不会相等,因为堆损坏引入的列表中存在一些循环。
我不认为这与锁有任何关系,否则我们会看到一些原子指令(例如cmp ebx, eax
,lock cmpxchg
等)或调用其他同步函数。
答案 1 :(得分:0)
我有一个与文件关闭功能相同的情况。在我的情况下,我通过定位嵌入其他函数体的close函数来解决而不是拥有自己的函数。
我也很怀疑 (1)正在复制的文件的名称(2)Windows调度(文件IO在下一个任务处理开始之前没有完成.Windows调度和多线程是幕后的,因此很难验证,但是当我尝试在循环中保存ASCII中的许多数据时,我遇到类似的问题。在这种情况下保存二进制解决了。)
我的环境,IDE:Visual Studio 2015,操作系统:Windows 7,语言:C ++