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

时间:2015-05-30 17:39:38

标签: c debugging gdb printf race-condition

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

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

查看其他选项,我已经看到使用 gdb 可以使用断点来打印某些内容然后自动继续执行:

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

这比我的代码中放置printf更好吗?

我知道 gdb 还有一个Tracepoints,但它们只适用于gdbserver,这是我目前希望避免的额外级别的复杂功能。

其他信息:应用程序是用C语言编写的,它可以在Linux上运行。

2 个答案:

答案 0 :(得分:2)

由于你在Linux上,我会推荐ThreadSanitizer。这是使用最新版本的gcc或clang并将-fsanitize = thread传递给构建版本。这不是printf repacment,但应明确告诉您代码中的任何竞争条件。即使您使用多线程代码解决了这个问题,也可以使用此工具。或者,或者另外,我在Valgrind的http://valgrind.org Data Race Detector中取得了不错的成绩,但我会从ThreadSanitizer开始。

答案 1 :(得分:2)

  

这比将printf放入我的代码更好吗?

不,它的很多更糟糕。在GDB中遇到的每个断点都会触发以下事件链:

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

这比简单的printf调用至少要贵一个数量级且更具破坏性,并且很可能隐藏您尝试调试的任何种族。

最重要的是,GDB通常完全不适合用于调试数据竞赛。

我是Christopher Ian Stern推荐的ThreadSanitizer推荐。

  

这个bug的唯一问题是我在生产机器上进行调试,我无法安装其他SW。

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

其次,ThreadSanitizer会检测数据竞争,即使它们不会导致可见行为更改。很可能你根本不需要在你的生产机器上运行:只需在你的开发机器上运行测试(你进行测试,对吧?)可能证明是足够的。