调试竞争条件时打印信息的最佳方式

Best way to print information when debugging a race condition

我正在调试应用程序以修复我怀疑由竞争条件引起的分段错误。

我想在代码中添加一些打印语句,但根据经验我知道不建议添加对 printf 的调用,因为这可能会改变线程的行为并且在某些情况下会隐藏错误。

查看其他选项,我看到 gdb 可以使用断点打印一些东西然后自动继续执行:

break foo
commands
silent
printf "Called foo: x is %d\n",x
cont
end

这比在我的代码中加入 printf 更好吗?

我知道 gdb 也有一个 Tracepoints 但它们只能与 gdbserver 一起使用,这是我目前希望避免的额外复杂程度.

附加信息:该应用程序是用 C 语言编写的,在 Linux.

上运行

既然你在 Linux,我会推荐 ThreadSanitizer。那是使用最新版本的 gcc 或 clang 并将 -fsanitize=thread 传递给构建。这不是 printf 的重新安排,但应该明确告诉您代码中的任何竞争条件。如果您正在使用多线程代码,即使在您解决了这个问题之后,您也会希望使用这个工具。或者,或者另外,我使用 Valgrind 的 http://valgrind.org 数据竞争检测器取得了不错的结果,但我会从 ThreadSanitizer 开始。

Is this any better then putting a printf in my code?

不,更糟。 GDB 中命中的每个断点都会触发以下事件链:

  • 上下文从 运行ning 线程切换到 GDB
  • GDB 停止所有其他线程(假设默认全停止模式)
  • GDB 评估断点命令
  • GDB 恢复所有线程(这本身就是一个复杂的多步骤过程,我不会在这里赘述)。

这比一个简单的 printf 调用至少要昂贵和破坏一个数量级,并且很可能隐藏您试图调试的任何竞争。

总的来说,GDB 完全不适合调试数据竞争。

我支持 Christopher Ian Stern 推荐的 ThreadSanitizer。

The only problem with this bug is that I am doing the debug on a production machine where I cannot install other SW.

首先,ThreadSanitizer 检测您现有的程序。它有一个 运行time 库,但可以静态链接到您的二进制文件中。您无需在生产机器上安装任何东西。

其次,ThreadSanitizer 会检测数据竞争,即使它们不会导致 可见 行为变化。结果很可能你根本不需要 运行 在你的生产机器上:简单地 运行 测试(你 有测试,对?)在您的开发机器上可能就足够了。