Мне нужен способ разветвить текущий процесс на другой виртуальный терминал. На самом деле я хочу создать дочерние элементы моего процесса в отдельных панелях 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 текущего процесса. Это переместит ребенка в свою группу, и 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/