处理A fork()
进程B。
流程A死亡,因此init
采用B.
看门狗创建进程C.
C在某种程度上可以从init
采用B吗?
更新:
或者甚至可以让C直接采用B(当A死亡时),如果C在A死之前创建,而init
没有成为B的中间父级?
更新-1:
另外,我很感激为什么有可能采用我所描述的方式采用一种方法可能是一件坏事或难以实现的任何评论。
Update-2 - 用例(父级和子级引用进程):
我有一个应用程序使用父级管理一大堆子,这依赖于父级的管理工具。为了完成其工作,父母依靠通过孩子的终止通知,这通过接收相关的SIGCHLD
信号来完成。
如果父母本身因某些事故(包括segfaulting)而死亡,我需要重启整个“家庭”,因为现在不可能在孩子终止时触发某些事情(这也可能是由于段错误)。
在这种情况下,我需要关闭所有孩子并重新启动系统。
避免这种情况的一种可能方法是,有一个备用过程可以接管死去的父母的角色...... - 如果它可以再次接收步骤孩子的SIGCHLD
信号!
答案 0 :(得分:16)
不,绝对不可能。没有一些讨厌的竞争条件,它也无法实现。制作这些API的POSIX人永远不会创造具有固有竞争条件的东西,所以即使你没有被打扰,你的内核也不会很快得到它。
一个问题是pids会被重复使用(它们是一种稀缺的资源!),你也无法获得一个句柄或锁定;这只是一个数字。因此,比方说,在代码中的某个位置,您有一个变量,您可以在其中放置要重新显示的进程的pid。然后你拨打make_this_a_child_of_me(thepid)
。那会发生什么?与此同时,其他进程可能已退出,thepid
已更改为引用其他进程!哎呀。如果没有对unix处理进程的方式进行大规模重组,就无法提供make_this_a_child_of_me
API。
请注意,{child}对孩子pid的整个处理正是为了防止这个问题:进程表中仍然存在僵尸进程,以防止其pid被重用。然后,父母可以通过其pid引用其子项,确信该过程不会退出并重新使用子pid。如果子进程退出,则其pid将保留,直到父进程捕获SIGCHLD或等待它。一旦获得该进程,其pid立即被抢夺,以便其他程序在fork时开始使用,但父母保证已经知道它。
对更新的响应:考虑一个更复杂的方案,其中进程被重新分配给它们的下一个祖先。显然,在每种情况下都无法做到这一点,因为你经常想要一种让孩子不认识的方法,以确保你避免僵尸。 init非常好地履行了这个角色。因此,某个流程必须采用某种方式来指定它是否采用其孙子(或更低版本)。这种设计的问题与第一种情况完全相同:你仍然获得竞争条件。
如果它再次由pid完成,那么祖父母将自己暴露于竞争条件:只有父母能够获得一个pid,所以只有父母真正知道pid与哪个进程有关。因为祖父母无法获得,所以不能确定孙子进程没有从它想要采用的那个改变(或者取消,取决于假设的API如何工作)。请记住,在负载很重的机器上,没有什么可以阻止一个进程从CPU上取下几分钟,并且整个负载可能在那段时间内发生了变化!不理想,但POSIX必须考虑到它。
最后,假设这个API不能通过pid工作,但通常会说,“将所有孙子送给我”或“将它们发送给init”。如果在生成子进程后调用它,那么就像以前一样获得竞争条件。如果它之前被调用过,那么整个事情就没用了:你应该能够重新构建你的应用程序以获得相同的行为。也就是说,如果你在开始产生儿童进程之前就已经知道谁应该是谁的父母,为什么你不能继续前进并在第一时间以正确的方式创建它们?管道和IPC确实能够完成所有必需的工作。
答案 1 :(得分:8)
没有办法以你所描述的方式强制执行Reparenting。
答案 2 :(得分:0)
我不知道执行此操作的好方法,但是拥有它的一个原因是,运行的进程可以独立运行,也可以为父进程添加功能。收养将作为事件的结果发生,由(尚未)孩子知道,但不是父辈知道。即将成为孩子的孩子会向父母发送信号。父母会收养(或不收养)孩子。一旦成为父进程的一部分,父/子进程将能够对事件做出反应,而当单独站立时,父进程/子进程都不会对事件做出反应。
可以将这种对接行为编码为应用程序,但我不知道如何实时进行。还有其他方法可以实现相同的功能。可以接受对接子对象的父母可以以其父母以前不知道的新颖方式扩展其功能。