Как разветвить процесс на другой виртуальный терминал

Мне нужен способ разветвить текущий процесс на другой виртуальный терминал. На самом деле я хочу создать дочерние элементы моего процесса в отдельных панелях tmux, но знание того, как перейти на другую консоль, подойдет, остальное должно быть легко.


84
1

Ответ:

Решено

Перенос одного процесса в другой терминал

Сначала давайте посмотрим, как перенести один процесс в другую консоль. В 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/


Интересные вопросы для изучения