背景
我正在用C语言编写一个共享库,与LD_PRELOAD
动态链接,用于拦截和覆盖预加载应用程序的网络调用,例如socket()
,connect()
, recv()
,send()
等
在库的init中,我启动了一个pthread_create()
的线程。该线程轮询一些内核内存,该内存映射到用户空间。
该库的通用性足以处理 - 但不限于 - 网络基准测试应用程序,例如 netperf , iperf , sockperf
我的问题
一切都很好,大多数情况下生活都很美好,除了一个。 Deamonized应用程序。例如,如果我将 netserver ( netperf 基准测试应用程序的服务器端)作为deamon启动,即没有-D
参数,那么首先要做的事情之一应用程序执行的操作是fork()
。在fork上,使用exit(EXIT_SUCCESS)
关闭父级,并且子级侦听连接。父退出的事实会导致我的轮询线程被杀死。
所以我想要实现的是让孩子在父母已经离开的情况下产生一个新的轮询线程。我可以截取并覆盖fork()
电话,但从根本上说,我怎样才能让孩子知道父母是否已经离开?我不能采取任何假设,因为库必须是通用的。
感谢。
答案 0 :(得分:5)
您可以定期轮询getppid()函数。一旦它开始返回'1'(init进程的id) - 你的父母就死了。
<强>更新强>
摘自'man pthread_create':
新线程以下列方式之一终止:...
- 进程中的任何线程都调用exit(3)或主线程 从main()执行返回。这导致所有的终止 这个过程中的线程。
因此,如果你的线程是由调用exit的netserver进程创建的 - 是的,这个线程将被终止
答案 1 :(得分:1)
您可以使用ptread_atfork(3)
在孩子中启动您的主题。
答案 2 :(得分:1)
大约一年后,我得到了我自己的问题的答案,即“儿童过程如何知道其父母死了?”
那么,孩子可以使用getppid()
询问其父母的PID是什么。如果父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 init时,我只需要调用:
__register_atfork(NULL, NULL, child_fork, NULL)
但是,此解决方案并未涵盖所有情况。例如,如果父母有多个孩子怎么办?我是否真的希望他们全部启动投票线程?
现在它对我来说是一个可以接受的解决方案,虽然它并不理想。