我现在正在调试一个利用许多不同线程的程序。
有时会抛出异常。问题是没有办法知道什么线程导致了问题...
有人知道抛出异常后获取堆栈跟踪的简单方法吗?我想过简单地写一个调试消息,但它会是一个巨大的:-)我想有比这更好的技术......
我正在使用visual studio 2008 - 原生c ++项目......
答案 0 :(得分:5)
除非我非常错误,否则您需要知道哪个线程触发了异常才能使用Visual Studio调试器的调用堆栈视图,这显然是您目前所处的catch-22情况。
我要尝试的一件事是看看是否可以在抛出异常时让调试器中断(使用Debug> Exceptions)。你必须明确地启用它,但如果你知道抛出了什么类型的异常,这可能会让你找出抛出它的位置。
除此之外,在异常的构造函数中放置一个断点(如果它是你自己的一个)也应该允许你找出触发它的位置。
如果这些方法对您不起作用,我会按照您的建议查看调试消息。
答案 1 :(得分:2)
使用免费的Microsoft WinDBG可以轻松实现这一点。您还需要为Windows版本安装符号,如果您还没有。{/ p>
只需将WinDBG设置为Crash Dump工具即可。我使用此注册表设置:(您可能希望编辑路径)
CrashDumpSettings.reg
:Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug]
"Auto"="1"
"Debugger"="C:\\progra~1\\debugg~1\\cdb.exe -p %ld -e %ld -g -y SRV*c:\\mss*http://msdl.microsoft.com/download/symbols -c \"$<c:\\Dumps\\CrashDump.cdbscript\""
以下是CrashDump.cdbscript
的外观:( 这基本上就是我使用的......根据需要编辑路径。)
CrashDump.cdbscript
:.sympath+ c:\windows\symbols;c:\some\path\to\symbols\for\your\project
as /c CrashFirstModule .printf "%mu", @@c++((*(ntdll!_LDR_DATA_TABLE_ENTRY**)&@$peb->Ldr->InLoadOrderModuleList.Flink)->BaseDllName.Buffer)
.logopen /t c:\dumps\${CrashFirstModule}_process.log
.kframes 100
!analyze -v
~*kv
lmv
.logclose
.dump /mhi /u /b c:\dumps\${CrashFirstModule}_mini.cab
.dump /mhia /u /b c:\dumps\${CrashFirstModule}_full.cab
q
并且您获得了一个很好的日志文件和一些转储,您可以使用它们来查看WinDBG发生异常时的进程状态。日志文件将分析发生的错误,包括导致错误的代码行。它还将列出每个线程的调用堆栈。在调用堆栈列表中,其编号旁边带有#
的线程是导致异常的线程。这些文件中有一大堆信息。我建议约翰罗宾斯选择Debugging Applications for Microsoft .Net and Microsoft Windows。这是一本关于调试的好书,即使它来自几年前。您可以从Amazon获得约20美元。
答案 2 :(得分:1)
这个库看起来很合适:
http://www.codeproject.com/KB/threads/StackWalker.aspx
Jochen Kalmbach看起来已经完成了包装低级dbghelp.dll接口复杂性的非常彻底的工作。
答案 3 :(得分:1)
你可以在异常构造函数中设置一个断点(即你要抛出的对象)。
这当然假设您有一个共同的异常层次结构。
答案 4 :(得分:0)
您可以使用“例外”对话框(Debug
| Exceptions...
菜单项,或Ctrl+Alt+E
或Ctrl+D E
,具体取决于您的键盘绑定)来将运行代码分解为调试位置特定异常被抛出的那一刻?
答案 5 :(得分:0)
如果您无法获得调试器来捕获正在发生的事情......并且您无法打印堆栈跟踪和线程......
我的猜测是你必须加入一些好的肘部油脂和努力工作。首先要了解系统。一旦理解了系统,尝试将系统分成两半。有效的部分和不起作用的部分。然后继续尝试这样做,直到你深入研究问题为止。
当您向下钻取足够的时间时,尝试使用try / catch包围可疑代码...希望您可以使用调试器来停止执行并查看发生了什么。
答案 6 :(得分:-2)
异常本身具有属性StackTrace ...所以你只需要返回ToString()。
但我相信你的问题更像是如何捕捉随机异常。如果是这样,我所做的就是将所有主要代码放在try / catch中。我真的不太确定是否在其他线程中抛出异常,这种技术会起作用。
您还应该捕获一个不是从Exception派生的ApplicationExeption。