我需要一种方法将当前进程分叉到另一个虚拟终端中。实际上,我想将我的进程的子进程生成到单独的 tmux 窗格中,但是知道如何分叉到另一个控制台就可以了,其余的应该很容易。
首先让我们看看如何将单个进程抓取到另一个控制台中。在 Linux 中,您可以使用 reptyr 将进程重新附加到另一个终端。这相当容易。
假设这是您的主程序
#!/usr/bin/perl
print "My PID is $$\n"; # print current process PID;
sleep 10;
while(1){
print ++$i, "\n";
sleep 1;
}
它会打印自己的PID,然后在一段时间后开始计算秒数。
你应该跑
reptyr [PID-number]
在新终端中(将程序打印的PID放在
[PID-number]
的位置),你会看到我们的主程序将被移动到新终端中。
非常简单
如果您尝试使用新分叉来完成此操作,
reptyr
将失败并出现以下错误:
[-] Process 739989 (test2.pl) shares 739990's process group. Unable to attach.
(This most commonly means that 739990 has sub-processes).
Unable to attach to pid 739990: Invalid argument
当您创建分叉时,它开始与父进程共享一个组(解释进程组内容的文章链接位于本文末尾)。由于某种原因,您
reptyr
无法抢夺属于某个组的进程。要在该子进程上使用 reptyr
,您应该将其取消分组,或者更精确地通过调用 setpgid($$, $$)
将其设置为自己的组,这会将当前进程分配到 ID 为当前进程的进程 ID 的组。这会将孩子移动到自己的组中,reptyr
将能够“抢夺”它。
#!/usr/bin/perl
use POSIX;
$pid = fork();
if ($pid)
{
# parent process
print "Child PID is $pid\n";
sleep 10;
while (1) {print ".\n"; sleep 1};
} else
{
# child process
(setpgid($$,$$) != -1) || die "Can't set own group: $!";
sleep 10;
while (1) {print ++$i,"\n"; sleep 1};
}
这里父进程打印点,子进程计算秒。它还在开始时打印子 PID。
如果您什么都不做,父级和子级的输出将混合在您运行它的终端中。但如果你跑步
reptyr [child-PID-number]
在新终端中(将程序打印的子PID放在
[child-PID-number]
的位置),您将看到父程序的输出(点)将保留在旧终端中,而子程序的输出(数字)将移动到新航站楼。
为了更好地理解流程组的内容,您应该阅读这篇文章:https://blog.nelhage.com/2011/02/changing-ctty/