7

背景

我正在用 C 编写一个共享库,与 动态链接LD_PRELOAD,这意味着拦截和覆盖来自预加载它的应用程序的网络调用,例如socket(), connect(), recv(),send()等。

在库的初始化中,我使用pthread_create(). 该线程轮询一些映射到用户空间的内核内存。

该库具有足够的通用性,可以处理(但不限于)网络基准应用程序,例如netperfiperfsockperf

我的问题

一切正常,在大多数情况下,生活都是甜蜜的,除了一个。去魔化的应用程序。例如,如果我启动netservernetperf基准测试应用程序的服务器端)作为守护程序,即没有-D参数,应用程序首先要做的事情之一就是调用fork(). 在 fork 上,父级使用关闭exit(EXIT_SUCCESS),子级监听连接。父母退出的事实杀死了我的轮询线程。

所以我想要实现的是让孩子在父母离开时产生一个新的轮询线程。我可以拦截和覆盖fork()电话,但从根本上说,我怎样才能让孩子知道父母是否已经走了?我不能做任何假设,因为库必须是通用的。

谢谢。

4

3 回答 3

5

您可以定期轮询 getppid() 函数。一旦它开始返回 '1' (初始化进程的 id) - 你的父母已经死了。

更新

摘自“man pthread_create”:

新线程以下列方式之一终止: ...

  • 进程中的任何线程调用exit(3),或者主线程执行main() 的返回。这会导致进程中的所有线程终止。

因此,如果您的线程是由调用 exit 的 netserver 进程创建的 - 是的,该线程将被终止

于 2012-09-22T01:18:05.727 回答
1

您可以使用ptread_atfork(3)在孩子中启动您的线程。

于 2012-09-22T01:30:52.720 回答
1

大约一年后,我有了自己问题的答案,即“子进程如何知道其父进程已死?”

好吧,孩子可以使用getppid(). 如果父 PID 为 1,则表示子进程已重新成为该进程的父init进程。于是,父母走了。

例如:

void child_fork(void)
{
    int parent_pid;
    usleep(1);
    parent_pid = (int)getppid();

    if (parent_pid == 1)
        run_my_polling_thread();
}

注意:当一个进程分叉时,父进程会进入睡眠状态。子进程先运行,再唤醒父进程(对于Copy-on-Write优化,这里不再赘述)。这里的usleep(1)调用是为了让孩子立即入睡,以便父母有时间醒来并终止。在孩子醒来之前,它将重新成为init.

现在,在 lib 初始化时,我只需要调用:

__register_atfork(NULL, NULL, child_fork, NULL)

但是,此解决方案并未涵盖所有情况。例如,如果父母有多个孩子怎么办?我真的希望他们都启动一个投票线程吗?

现在这对我来说是一个可以接受的解决方案,尽管它并不理想。

于 2013-08-06T18:18:31.800 回答