C++ 带线程的Fork和core转储
之前和之前都有人提出过与此问题类似的观点,我知道Google coredump库(我对其进行了评估,发现其不足,但如果我能更好地理解这个问题,我可能会尝试进行这方面的工作) 我希望在不中断进程的情况下获得正在运行的Linux进程的核心转储。自然的方法是说:C++ 带线程的Fork和core转储,c++,c,linux,pthreads,coredump,C++,C,Linux,Pthreads,Coredump,之前和之前都有人提出过与此问题类似的观点,我知道Google coredump库(我对其进行了评估,发现其不足,但如果我能更好地理解这个问题,我可能会尝试进行这方面的工作) 我希望在不中断进程的情况下获得正在运行的Linux进程的核心转储。自然的方法是说: if (!fork()) { abort(); } 由于分叉进程获得了原始进程内存的固定快照拷贝,我应该得到一个完整的内核转储,并且由于拷贝使用了写时拷贝,所以通常应该比较便宜。但是,这种方法的一个关键缺点是fork()只对当前线程进行分叉
if (!fork()) { abort(); }
由于分叉进程获得了原始进程内存的固定快照拷贝,我应该得到一个完整的内核转储,并且由于拷贝使用了写时拷贝,所以通常应该比较便宜。但是,这种方法的一个关键缺点是fork()
只对当前线程进行分叉,而分叉副本中不存在原始进程的所有其他线程
我的问题是,是否有可能以某种方式获得其他原始线程的相关数据。我不完全确定如何解决这个问题,但我提出了几个子问题:
如果这是可能的,那么可能只需要将其他线程的数据附加到核心转储。但是,如果该数据已经在fork点丢失,那么这种方法似乎没有任何希望。如果您打算在非特定位置获取核心文件,并且只获取正在运行的进程的核心映像而不终止,那么您可以使用
如果您打算在特定位置(条件)获取核心文件,并且仍然继续运行该流程,那么一种粗略的方法是从该位置以编程方式执行 一种更经典、更干净的方法是检查gcore使用的API并将其嵌入到应用程序中,但与大多数情况下的需要相比,这太费劲了
嗯 当您使用
fork
时,您将获得正在运行的进程内存的完整副本。这包括所有线程堆栈(毕竟,您可以将有效指针插入它们)。但只有调用线程继续在子线程中执行
你可以很容易地测试这个。制作一个多线程程序并运行:
pid_t parent_pid = getpid();
if (!fork()) {
kill(parent_pid, SIGSTOP);
char buffer[0x1000];
pid_t child_pid = getpid();
sprintf(buffer, "diff /proc/%d/maps /proc/%d/maps", parent_pid, child_pid);
system(buffer);
kill(parent_pid, SIGTERM);
return 0;
} else for (;;);
因此,所有内存都在那里,当您创建核心转储时,它将包含所有其他线程堆栈(前提是您的最大核心文件大小允许)。唯一缺少的是它们的寄存器集。如果您需要这些,您必须ptrace
您的家长才能获得它们
您应该记住,核心转储的设计目的并不是包含多个线程的运行时信息——导致核心转储的线程
要回答您的其他一些问题:
您可以通过执行/proc/[pid]/tasks
来枚举线程,但在ptrace
之前,您无法识别它们的堆栈基础
是的,您可以从分叉进程完全访问其他线程堆栈快照(见上文)。确定它们并不简单,但只要核心文件大小允许,它们确实会被放入核心转储。如果可以的话,最好在创建时将它们保存在全局可访问的结构中。您熟悉进程检查点重新启动吗?特别是?在我看来,这可能为你提供一个简单的选择 我希望在不中断进程的情况下获取正在运行的Linux进程的核心转储,并以某种方式获取其他原始线程的相关数据 忘记不要打断这个过程。如果您仔细想想,核心转储必须在转储期间中断进程;因此,您的真正目标必须是尽量缩短这种中断的持续时间。您最初使用
fork()
的想法确实会中断这个过程,它只会在很短的时间内中断
fork()
只保留执行实际调用的线程,其余线程的堆栈丢失
假设CRIU不合适,我将使用以下程序:
- 有一个父进程,每当子进程停止时,它都会生成子进程的核心转储。(请注意,可能会生成多个连续停止事件;应仅对第一个停止事件执行操作,直到下一个继续事件。) 您可以使用检测停止/继续事件
- 可选:用于将进程限制为单个CPU,以及(或者)将进程优先级降低为
您可以从父进程执行此操作,它只需要有效和允许的集合中的空闲
功能(您可以使用CAP\u SYS\u NICE
setcap'CAP\u SYS\u NICE=pe'父二进制文件赋予它,如果您像大多数当前Linux发行版一样启用了文件系统功能) 这样做的目的是在一个线程决定它想要快照/转储的时刻和所有线程停止的时刻之间最小化其他线程的进度。我还没有测试这些更改需要多长时间才能生效——当然,它们最早只发生在当前时间段的末尾。因此,这一步可能应该提前一点完成 就我个人而言,我不介意。在我的四核机器上,仅以下
就可以在线程之间产生类似于互斥或信号量的延迟,因此我看不到任何延迟SIGSTOP