使用 GDB 恢复实时数据

发布于 2023-01-27 01:20:32 字数 2189 浏览 121 评论 0

我最近遇到个问题,有一个 运行很长时间的程序 ,它的输出被卡在一个C语言 FILE 变量的 buffer 中了,这个程序已经运行两天了,它会把结果直接输出来,但是最后几k的内容要等到程序完成它的清理动作并退出后才能输出来,而这个清理动作耗时可能要花几天(甚至更多),这个问题本身要修复很简单 — 这个清理的动作其实完全是没有必要的 — 但是我不想又要花两天的时间把结果重新再计算一遍。

下面这段代码简单模拟一下这个问题。第一个循环代表了长时间的运算过程,而后面的无限循环代表了那个无尽的清理动作。

#include <stdio.h>

int
main(void)
{
  /* Compute output. */
  for (int i = 0; i < 10; i++)
    printf("%d/%d ",i,i * i);
  putchar('\n');

  /* "Slow" cleanup operation ... */
  for (;;)
    ;
  return 0;
}

Buffered Output Review

printf and putchar 这两个 C库函数,都会以某种方式来缓存输出的内容。这意味着不是每次调用这些函数都会实际输出数据。另一方面,POSIX定义的函数 readwrite 则是不带buffer的系统调用,由于系统调用相对来说比较昂贵,因此一般会用带缓存的输入/输出来将大量针对小 buffer 的系统调用转换成一个针对大buffer的系统调用。

一般来说,若程序的标准输出为终端的话,它是按行来缓存的,毕竟当程序完成了一行的输出内容后,用户很可能立即就想看到输出结果,因此,若你编译该程序后是在终端上直接运行改程序的话,那么很可能在程序陷入无限循环之前就已经把结果输出来了。

$ cc -std=c99 example.c
$ ./a.out
0/0 1/1 2/4 3/9 4/16 5/25 6/36 7/49 8/64 9/81

然而若把标准输出重定向到文件或管道中的话,这个输出很有可能就会被缓存起来了,这个缓存大小一般为 4KB,这样一来,不管你等多长时间,改程序的输出始终都为空,真正的输出内容被卡在进程内存中的一个 FILE 对象的 buffer 中了。

$ ./a.out > output.txt

修复这个问题的主流方法是调用 fflush 函数,在开始一段耗时漫长而无输出结果的操作前可以用它来强行将buffer中的内容输出,可惜,我早在两天前并没有想到这一出。

Debugger to the Rescue

幸运的是,有一个东西可以暂停正在运行的程序并帮我们维护程序的状态:那就是调试器。

第一步,找出进程号(上面输入 output.txt 的那个进程)。

$ pgrep a.out
12934

现在让启动 GDB,让它 attach 那个进程,这会暂停程序的运行。

$ gdb ./a.out
Reading symbols from ./a.out...(no debugging symbols found)...done.
gdb> attach 12934
Attaching to program: /tmp/a.out,process 12934
... snip ...
0x0000000000400598 in main ()
gdb>

到了这一步,我就可以手工检查 stdout 的FILE结构,并从中抽取出buffer中的内容了,不过最简单的方法是执行我一开始忘掉的条语句 fflush(stdout)

gdb> call fflush(stdout)
$1 = 0
gdb> quit
Detaching from program: /tmp/a.out,process 12934

程序依旧还在执行,我们已经得到结果了。

$ cat output.txt
0/0 1/1 2/4 3/9 4/16 5/25 6/36 7/49 8/64 9/81

原文地址: http://nullprogram.com/blog/2015/09/15/

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

九八野马

暂无简介

文章
评论
29 人气
更多

推荐作者

櫻之舞

文章 0 评论 0

弥枳

文章 0 评论 0

m2429

文章 0 评论 0

野却迷人

文章 0 评论 0

我怀念的。

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文