不,绝对不可能。如果没有一些讨厌的竞争条件,它也无法实现。制作这些 API 的 POSIX 人员永远不会创建具有固有竞争条件的东西,所以即使您不介意,您的内核也不会很快得到它。
一个问题是 pid 被重复使用(它们是一种稀缺资源!),而且您也无法获得句柄或锁定一个;这只是一个数字。因此,比如说,在您的代码中的某处,您有一个变量,您可以在其中放置要重新设置的进程的 pid。然后你打电话make_this_a_child_of_me(thepid)
。那时会发生什么?与此同时,其他进程可能已经退出并thepid
更改为引用其他进程!哎呀。make_this_a_child_of_me
如果不对unix 处理进程的方式进行大规模重组,就无法提供API。
请注意,对子 pid 进行 ing 的整个处理wait
正是为了防止这个问题:进程表中仍然存在僵尸进程,以防止其 pid 被重用。然后,父进程可以通过它的 pid 引用它的子进程,确信进程不会退出并让子进程 pid 重用。如果子进程退出,它的 pid 将被保留,直到父进程捕获 SIGCHLD 或等待它。一旦进程被收割,它的 pid 立即可供其他程序在它们分叉时开始使用,但父进程保证已经知道它。
对更新的响应:考虑一个更复杂的方案,其中进程被重新分配给它们的下一个祖先。显然,这不可能在所有情况下都这样做,因为您经常想要一种与孩子断绝关系的方式,以确保您避免僵尸。init 很好地完成了这个角色。因此,流程必须通过某种方式来指定它打算收养或不收养其孙辈(或更低)。这种设计的问题与第一种情况完全相同:您仍然会遇到竞争条件。
如果再次由 pid 完成,则祖父母将自己暴露于竞争条件:只有父母能够获得 pid,因此只有父母真正知道 pid 与哪个进程一起使用。因为祖父母不能收割,所以不能确定孙进程没有改变它打算采用的进程(或不承认,取决于假设的 API 的工作方式)。请记住,在负载很重的机器上,没有什么可以阻止进程在几分钟内从 CPU 中取出,而整个负载可能在这段时间内发生了变化!不理想,但 POSIX 必须考虑到这一点。
最后,假设这个 API 不能通过 pid 工作,而只是一般地说,“将所有孙子发送给我”或“将它们发送给 init”。如果在子进程生成后调用它,那么您会像以前一样获得竞争条件。如果之前调用过它,那么整个事情就没用了:您应该能够稍微重构您的应用程序以获得相同的行为。也就是说,如果您在开始生成子进程之前就知道谁应该是谁的父进程,那么为什么不能一开始就以正确的方式创建它们呢?Pipes 和 IPC 确实能够完成所有必需的工作。