我正在尝试调试很少死锁的自定义线程池实现。所以我不能使用像gdb这样的调试器,因为我在遇到死锁之前点击了100次“启动”调试器。
目前,我在shell脚本的无限循环中运行线程池测试,但这意味着我看不到变量等等。我正在尝试std::cout
数据,但这会减慢线程并减少死锁的风险,这意味着我可以在获取消息之前等待1小时的无限。然后我没有得到错误,我需要更多的消息,这意味着再等一个小时......
如何有效地调试程序,以便它一遍又一遍地重启直到它死锁? (或者我应该用所有代码打开另一个问题以获得一些帮助?)
提前谢谢!
奖金问题:如何使用std::condition_variable
检查一切正常?您无法确定哪个线程处于睡眠状态或wait
条件下是否出现竞争条件。
答案 0 :(得分:17)
有两种基本方法:
gdb program -ex 'run <args>' -ex 'quit'
应该在调试器下运行程序,然后退出。如果程序仍然以某种形式存在(段错误,或者您手动将其打破),则会要求您进行确认。gdb <program> <pid>
运行以附加到正在运行的程序 - 只需等待死锁然后附加即可。当附加的调试器导致更改时间并且您无法再重新编写错误时,这尤其有用。通过这种方式,您可以在循环中运行它并在喝咖啡时等待结果。顺便说一句 - 我发现第二种选择更容易。
答案 1 :(得分:5)
如果这是某种功课 - 再次使用更多调试重新启动将是一种合理的方法。
如果有人为你等待的每一个小时付钱,他们可能更愿意投资支持replay-based debugging的软件,即一个记录程序所做的一切的软件,每条指令,并允许你重播它一次又一次,来回调试。因此,不是添加更多调试,而是记录发生死锁的会话,然后在发生死锁之前开始调试。你可以随心所欲地来回走动,直到你终于找到了罪魁祸首。
链接中提到的软件实际上支持Linux和多线程。
答案 2 :(得分:2)
您可以使用https://stackoverflow.com/a/8657833/341065中显示的命令循环在GDB下运行测试用例:gdb --eval-command=run --eval-command=quit --args ./a.out
。
我自己使用过这个:(while gdb --eval-command=run --eval-command=quit --args ./thread_testU ; do echo . ; done)
。
一旦死锁并且没有退出,你可以通过 CTRL + C 中断它以进入调试器。
答案 3 :(得分:1)
查找死锁的简单快速调试是将一些全局变量修改为您要调试的位置,然后将其打印在信号处理程序中。您可以使用SIGINT(使用nMoments
打断时发送)或SIGTERM(杀死程序时发送):
int nMoments = 1000;
dataset = new DynamicTimeSeriesCollection(1, nMoments, new Second());
Calendar c = Calendar.getInstance();
c.setTime(new Date(0));
c.add(Calendar.SECOND, -nMoments);
dataset.setTimeBase(new Second(c.getTime()));
就像使用ctrl+c
中断程序时,您只看到所有调试变量的状态。
此外,您可以在shell循环中运行它:
int dbg;
int multithreaded_function()
{
signal(SIGINT, dbg_sighandler);
...
dbg = someVar;
...
}
void dbg_sighandler(int)
{
std::cout << dbg1 << std::endl;
std::exit(EXIT_FAILURE);
}
将永远运行您的程序,直到它失败(ctrl+c
是程序的退出状态,并在信号处理程序中退出EXIT_FAILURE。)
它对我来说效果很好,尤其是找出在锁定之前和之后传递了多少线程。
它非常质朴,但您不需要任何额外的工具,而且实施起来很快。
答案 4 :(得分:1)
基于Mozilla rr开源重播的调试
Hans mentioned replay based debugging,但有一个特定的开源实现值得一提:Mozilla rr
。
首先执行记录运行,然后您可以根据需要重复完全相同的运行,并在GDB中观察它,并保留所有内容,包括输入/输出和线程排序。
rr最初的动机是让间歇性故障的调试变得容易
此外,rr
使GDB反向调试命令(如reverse-next
)可以转到上一行,这样可以更容易地找到问题的根本原因。
以下是rr
的最小示例:How to go to the previous line in GDB?