我有一个有 2 个线程的程序,其中一个重绘显示(使用 ncurses),另一个在串行端口上运行 inout 处理,在进程中输出一些信息。
我发现,在某些时候,第二个线程会因我未知的原因而挂起。如果出现以下情况,如何找出问题的根源:
- 我无法调试第二个线程中发生的情况,因为 libthread_db 和 libpthread 在我的系统上不匹配,并且 gdb 拒绝提供线程调试。
- 挂起的线程通过对非阻塞文件描述符的
select
和read
顺序调用来执行处理。 - 使用 Cntrl-C 进入 gdb 并恢复程序后,线程不再卡住;并处理所有滞留在串口接收缓冲区的数据。
是否有任何提示或技巧可以帮助我找出问题的根源并确定挂起的原因?
更新。使用 strace 运行在跟踪中得到了这些行:
waitpid(-1, 0xbfdcdfd0, 0) = ? ERESTARTSYS (To be restarted)
--- SIGCHLD (Child exited) @ 0 (0) ---
--- SIGCONT (Continued) @ 0 (0) ---
据我所知,这对应于我看到程序挂起的时间,用C-z
暂停它并查看跟踪文件(在整个程序完成之前没有写入任何新内容) )。每次重新启动线程后都未挂起。
所以,这意味着存在“流氓”waitpid
调用。我确信它不会以裸露的形式出现在我的代码中的任何地方。遗憾的是 gdb 未能在其上设置断点 - 一定是某个地方的符号被剥离的问题。
最佳答案
Are there any tips or tricks that will help me get to the bottom of the issue and determine reason for hanging?
显而易见的答案是在挂起的线程上使用 strace
来查看它在做什么。
一个常见的错误是当您期望读取一定数量的字节时,然后像这样循环:
while (bytes_remaining > 0) {
int n = read(..., bytes_remaining);
if (n == -1) {
// handle read error ...
break;
}
// save data we just got ...
bytes_remaining -= n;
// loop to read more data
}
这里的问题是 read
可能会在 EOF
上返回 0
,并且您将永远循环。在 strace
中,这将立即变得显而易见。
如果不是这样,您可以做的另一件事(假设是 Linux)是将 GDB 附加到挂起的线程而不是进程。
关于c - 如何调试程序挂起的原因?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40024610/