我的一个应用程序中显然存在死锁问题,并开始调查EurekaLog堆栈跟踪。这是最近的一个:
Call Stack Information: -------------------------------------------------------------------------------------------------------------------------------------- |Address |Module |Unit |Class |Procedure/Method |Line | -------------------------------------------------------------------------------------------------------------------------------------- |*Exception Thread: ID=14208; Priority=0; Class=; [Main] | |------------------------------------------------------------------------------------------------------------------------------------| |7C82860C|ntdll.dll | | |KiFastSystemCall | | |7C827D27|ntdll.dll | | |ZwWaitForSingleObject | | |77E61C96|kernel32.dll | | |WaitForSingleObjectEx | | |77E61C88|kernel32.dll | | |WaitForSingleObject | | |77E61C7B|kernel32.dll | | |WaitForSingleObject | | |004151C4|MyApp.exe |sysutils.pas |TMultiReadExclusiveWriteSynchronizer|WaitForWriteSignal |16740[1] | |004151BC|MyApp.exe |sysutils.pas |TMultiReadExclusiveWriteSynchronizer|WaitForWriteSignal |16740[1] | |0041522C|MyApp.exe |sysutils.pas |TMultiReadExclusiveWriteSynchronizer|BeginWrite |16818[57] | |004323FB|MyApp.exe |Classes.pas |TDataModule |Create |11357[1] | |004323C0|MyApp.exe |Classes.pas |TDataModule |Create |11356[0] | |007D744D|MyApp.exe |uRORemoteDataModule.pas |TRORemoteDataModule |Create |163[1] | |007D7434|MyApp.exe |uRORemoteDataModule.pas |TRORemoteDataModule |Create |162[0] | |007DBFAB|MyApp.exe |Sentrol_Impl.pas | |Create_Sentrol |85[1] | |00646952|MyApp.exe |uROServer.pas |TROInvoker |CustomHandleMessage |726[11] | |00407BFA|MyApp.exe |system.pas |TInterfacedObject |_AddRef |17972[1] | |00404934|MyApp.exe |system.pas |TObject |GetInterface |9003[8] | |00407B1C|MyApp.exe |system.pas | |_IntfClear |17817[1] | |00404966|MyApp.exe |system.pas |TObject |GetInterface |9009[14] | |004048E8|MyApp.exe |system.pas |TObject |GetInterface |8995[0] | |00407BD7|MyApp.exe |system.pas |TInterfacedObject |QueryInterface |17964[1] | |77E61680|kernel32.dll | | |InterlockedDecrement | | |00407C10|MyApp.exe |system.pas |TInterfacedObject |_Release |17977[1] | |00407B2C|MyApp.exe |system.pas | |_IntfClear |17824[8] | |004067DF|MyApp.exe |system.pas | |_FinalizeArray |15233[100]| |00407B1C|MyApp.exe |system.pas | |_IntfClear |17817[1] | |00646577|MyApp.exe |uROServer.pas |TROClassFactoryList |FindClassFactoryByInterfaceName|619[17] | |77E6166C|kernel32.dll | | |InterlockedIncrement | | |00407BFA|MyApp.exe |system.pas |TInterfacedObject |_AddRef |17972[1] | |00646B72|MyApp.exe |uROServer.pas |TROInvoker |HandleMessage |758[1] | |006460C5|MyApp.exe |uROServer.pas | |MainProcessMessage |512[98] | |00645BAC|MyApp.exe |uROServer.pas | |MainProcessMessage |414[0] | |00647184|MyApp.exe |uROServer.pas |TROMessageDispatcher |ProcessMessage |929[2] | |00647130|MyApp.exe |uROServer.pas |TROMessageDispatcher |ProcessMessage |927[0] | |00647BCF|MyApp.exe |uROServer.pas |TROServer |IntDispatchMessage |1328[27] | |00647ABC|MyApp.exe |uROServer.pas |TROServer |IntDispatchMessage |1301[0] | |0064782F|MyApp.exe |uROServer.pas |TROServer |DispatchMessage |1170[11] | |006477B4|MyApp.exe |uROServer.pas |TROServer |DispatchMessage |1159[0] | |006477A9|MyApp.exe |uROServer.pas |TROServer |DispatchMessage |1152[1] | |0064779C|MyApp.exe |uROServer.pas |TROServer |DispatchMessage |1151[0] | |00659CB6|MyApp.exe |uROLocalServer.pas |TROLocalServer |SendRequest |57[1] | |00659CA4|MyApp.exe |uROLocalServer.pas |TROLocalServer |SendRequest |56[0] | |0065A009|MyApp.exe |uROLocalChannel.pas |TROLocalChannel |IntDispatch |99[10] | |005EE540|MyApp.exe |uROClient.pas |TROTransportChannel |Dispatch |1884[36] | |005EE3FC|MyApp.exe |uROClient.pas |TROTransportChannel |Dispatch |1848[0] | |005EEC8F|MyApp.exe |uROClient.pas |TROTransportChannel |Dispatch |2134[27] | |00616EC8|MyApp.exe |PCCS_Intf.pas |TSentrol_Proxy |GetNewValues |6585[7] | |007CBDB9|MyApp.exe |ETAROConnectionForm.pas |TROConnectionForm |SyncSentrolUpdateTimerTimer |855[16] | |7C82ABE5|ntdll.dll | | |RtlTimeToTimeFields | | |004D5D9C|MyApp.exe |Controls.pas |TControl |WndProc |5063[0] | |004DA05B|MyApp.exe |Controls.pas |TWinControl |WndProc |7304[111] | |7C81A3AB|ntdll.dll | | |RtlLeaveCriticalSection | | |0042659C|MyApp.exe |Classes.pas |TThreadList |UnlockList |3359[1] | |00426598|MyApp.exe |Classes.pas |TThreadList |UnlockList |3359[1] | |004935BC|MyApp.exe |Graphics.pas | |FreeMemoryContexts |5060[12] | |00493524|MyApp.exe |Graphics.pas | |FreeMemoryContexts |5048[0] | |004D9799|MyApp.exe |Controls.pas |TWinControl |MainWndProc |7076[6] | |004329F4|MyApp.exe |Classes.pas | |StdWndProc |11583[8] | |7739C09A|USER32.dll | | |CallNextHookEx | | |004B1343|MyApp.exe |ExtCtrls.pas |TTimer |Timer |2281[1] | |00404A30|MyApp.exe |system.pas | |_CallDynaInst |9159[1] | |004B1227|MyApp.exe |ExtCtrls.pas |TTimer |WndProc |2239[4] | |004329F4|MyApp.exe |Classes.pas | |StdWndProc |11583[8] | |7739C42C|USER32.dll | | |GetParent | | |7739C45C|USER32.dll | | |GetParent | | |773A16E0|USER32.dll | | |DispatchMessageA | | |773A16D6|USER32.dll | | |DispatchMessageA | | |004CC234|MyApp.exe |Forms.pas |TApplication |ProcessMessage |8105[23] | |004CC138|MyApp.exe |Forms.pas |TApplication |ProcessMessage |8082[0] | |004CC26E|MyApp.exe |Forms.pas |TApplication |HandleMessage |8124[1] | |004CC264|MyApp.exe |Forms.pas |TApplication |HandleMessage |8123[0] | |004CC563|MyApp.exe |Forms.pas |TApplication |Run |8223[20] | |004CC4B0|MyApp.exe |Forms.pas |TApplication |Run |8203[0] | |007F18B3|MyApp.exe |MyApp.dpr | | |215[65] |
堆栈跟踪似乎没有问题,直到第一次TTimer调用,之后它包含一些垃圾(?),但是结尾包含似乎持有主线程的锁。
我可以信任这个堆栈跟踪吗?如果没有,是什么导致这种情况以及如何避免它?
有关基于此堆栈跟踪的死锁的任何想法?我不太明白如何创建数据模块可能会死锁..
我正在使用Delphi 2007。
编辑:我发现一个案例,其中主要线程和RemObjects创建的线程之间共享DbExpress连接。在修复了一些小问题之后,应用程序已经运行了12个多小时没有问题。我会等一两天,看看问题是否真的消失了。
答案 0 :(得分:2)
我在关闭我的应用程序并在另一个线程中创建TForm或TDatamodule时遇到了同样的问题:因为应用程序正在终止,GlobalNameSpace(请参阅其他答案)被锁定(!),因此创建了我的TRORemoteDataModule另一个线程被锁定。因为我使用另一个锁等待该线程我遇到了死锁: - (。
在你的情况下,你必须看看其他线程,找到已经放置锁的那个(并且可能正在等待,否则你就不会有死锁)。我看到一个“SyncSentrolUpdateTimerTimer”:也许你在另一个线程的TDatamodule创建中做了一个TThread.Synchronize?
编辑:如果你想在死锁中查看其他线程的堆栈:
答案 1 :(得分:1)
我使用JCL进行堆栈跟踪日志记录,并使用map / jdbg文件。如果更改可执行文件并保留相同的映射文件,则堆栈日志将不正确,因为函数地址将不同。所以也许唯一的原因可能是这个。您还必须区分最后一个函数调用的真实堆栈跟踪和“调用历史记录”。我使用一个调用历史记录,它也列出了记录时调用的所有函数。就像你的TTimer一样。
典型的堆栈跟踪仅包含导致最后一个函数的函数调用。另一方面,“呼叫历史”包含在特定时间范围内被调用的所有功能。如果你在主线程旁边有辅助线程(比如TTimer),它也会记录他们的动作。我忘了在JCL中如何调用它,但如果你在stRawMode中跟踪它是默认行为。
最后,我可以从堆栈跟踪中看到WaitForSingleObject被调用,最好使用INFINITE参数,因此它永远不会超时。然后,WaitForSingleObject成为信号的条件永远不会被填满。
检查“TRORemoteDataModule”及其在构造函数中的作用。因为它似乎只从TDataModule继承并广告了它自己的一些逻辑。这应该是导致死锁的原因。
编辑:
好的,我检查了TDataModule代码:
constructor TDataModule.Create(AOwner: TComponent);
begin
GlobalNameSpace.BeginWrite;
try
CreateNew(AOwner);
if (ClassType <> TDataModule) and not (csDesigning in ComponentState) then
begin
if not InitInheritedComponent(Self, TDataModule) then
raise EResNotFound.CreateFmt(SResNotFound, [ClassName]);
if OldCreateOrder then DoCreate;
end;
finally
GlobalNameSpace.EndWrite;
end;
end;
它使用“GlobalNameSpace”单例接口,它是这样定义和实现的:
var
GlobalNameSpace: IReadWriteSync;
initialization
{$IFDEF MSWINDOWS}
GlobalNameSpace := TMultiReadExclusiveWriteSynchronizer.Create;
{$ENDIF}
...
所以这是你的锁。现在有趣的是它为什么会发生?它似乎是一个标准的VCL代码。也许你可以分享一些关于应用程序正在做什么的更多信息。
此外,您还可以查找调试输出。这在课程中定义:
procedure TMultiReadExclusiveWriteSynchronizer.BeginRead;
var
Thread: PThreadInfo;
WasRecursive: Boolean;
SentValue: Integer;
begin
{$IFDEF DEBUG_MREWS}
Debug('Read enter');
{$ENDIF}
...
因此,如果定义了“DEBUG_MREWS”,您将通过“OutputDebugString”获得调试信息。它应该为这个问题注入一些亮点。对我来说,这看起来像组件初始化竞争条件。 :)
答案 2 :(得分:1)
最后一次调用是在TMultiReadExclusiveWriteSynchronizer中,但它没有显示在哪种方法中。它可能会调用Windows同步功能,并在那里被阻止。您使用的是RemObjects库吗?那里发生了一些事情。 您可以使用SysInternals Process Explorer配置为下载Windows符号并在进程运行时检查堆栈跟踪,如果您转换.dbg格式的Delphi符号,您将拥有整个explict调用堆栈。
答案 3 :(得分:1)
你可以在调试器下重现这个挂起吗?如果是 - 则在GlobalNameSpace的Begin / EndWrite / Read方法上设置断点。输入每个断点的高级属性并打开“Break”选项并打开“Log call stack”选项。
现在,运行您的应用程序并让它挂起。检查事件窗口。您将看到GlobalNameSpace呼叫的完整历史记录。分析一下。某处肯定会有一些错误的电话。可能是最后一个。
或者,如果您使用的是Vista及以上版本,则可以使用Wait Chain Traversal功能,但我忘了,德尔福拥有它。只需让你的应用程序挂起并看到Threads窗口:应该有阻止的原因。
在极少数情况下,挂起可能是由内存损坏引起的。例如,坏代码可能会擦除/损坏“Free”/“Busy”标志,因此第一个尝试获取锁定的代码将永远等待,因为没有人释放锁定(因为它没有被锁定,它被损坏了。)