调试大型 C 应用程序时,我从 gdb
看到奇怪的行为:
我总是可以按 Ctrl+C
中断程序:
^C
Program received signal SIGINT, Interrupt.
0x76f58964 in select () at ../sysdeps/unix/syscall-template.S:81
81 in ../sysdeps/unix/syscall-template.S
(gdb)
但是,在程序运行足够长的时间(比如 > 1 天)后,我不能再轻易中断程序了。
当试图用 Ctrl+C
中断程序时,gdb
只显示
^C
Program received signal SIGINT, Interrupt.
并卡在那里几分钟到几小时。
如果花费的时间超过几分钟,我通常会打开另一个终端并手动终止 gdb
以便能够继续。
问题:这是 gdb
的预期行为吗?我可以设置一个选项来避免这种情况吗?
更多详情:
- 应用程序是
FTL
( https://github.com/pi-hole/FTL ) - 它是多线程的,使用
pthreads
- 在按下
Ctrl+C
后的等待时间内,gdb
的 CPU 使用率为 100%。
编辑:更多细节
我运行了 perf record -p $(pidof gdb)
大约 10 秒,而 gdb
被卡住了。 perf report
返回:
90,82% gdb gdb [.] find_thread_ptid
9,13% gdb gdb [.] ptid_equal
0,02% gdb gdb [.] iterate_over_threads
0,01% gdb [kernel.kallsyms] [k] run_timer_softirq
0,01% gdb gdb [.] 0x0016a9a4
0,00% gdb gdb [.] 0x0015a480
0,00% gdb gdb [.] 0x0016a998
0,00% gdb gdb [.] is_exited
几分钟后,gdb
完成,我运行了 info threads
,它仍然只显示三个线程(和以前一样):
(gdb) info threads
Id Target Id Frame
3 Thread 0x764b8460 (LWP 10114) "socket listener" 0x76f60260 in accept () at ../sysdeps/unix/syscall-template.S:81
2 Thread 0x76cb8460 (LWP 10113) "loganalyzer" 0x76f58964 in select () at ../sysdeps/unix/syscall-template.S:81
* 1 Thread 0x76e65000 (LWP 10098) "pihole-FTL" 0x76f58964 in select () at ../sysdeps/unix/syscall-template.S:81
最佳答案
gdb just shows ... and hangs there for several minutes up to hours.
一个猜测:您的程序创建了线程,但没有正确地加入和终止线程。
您可以通过运行该程序几个小时、使用 Control-C
中断它并发出 info threads
命令来确认或反驳这一点。
在 Linux 上,线程只是碰巧共享虚拟内存和文件描述符(以及控制终端)的进程。当您点击 Control-C
时,您的线程中只有 一个 接收到 SIGINT
。
在默认的all-stop
模式下,GDB 得到通知(由内核)一个线程有一个挂起的SIGINT
。然后,GDB 需要停止您进程的所有其他线程,这可能会花费大量时间。
不仅如此,GDB 可能不得不重复多次:当线程正在运行时,它们可能已经创建了新线程,现在也必须将其停止。
关于c - GDB 不会立即中断程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46502977/