使用perl进行过程控制和并发程序

时间:2014-09-18 15:44:46

标签: linux bash perl shell

我需要什么:  我的perl程序正在产生一些外部程序。然后它将监视外部程序并在它们因任何原因失败时重新启动它们。 perl程序不能等待它启动的进程。我不关心衍生程序的STDOUT或STDERR,并且想完全关闭它们的任何输出

到目前为止我的问题: 首先,我不了解流程抽象和流程管理的基础知识。我的perl程序及其子进程终止进程的不同场景将导致zombies' (曾经是我的perl程序的孩子的程序将被init

采用

使用open创建外部子程序

# please note I have simplified the shell commands for this example
$SIG{CHLD}='IGNORE';
open(my $ph, "-|", "./sc_serv --options") or die $!;
open(my $ph, "-|", "(ffmpeg --opt1 --opt2) | vlc --many-options --etc") or die $!;

如果查看下面pstree -p 6947的输出,您会发现我的perl程序创建了两个子进程sc_serv(6948)sh(6949)sh(6949)< - 此shell已创建,因为ffmpeg(6950)已通过管道传输到vlc(6952)(至少我相信这就是为什么需要shell,我不是百分百肯定。)

perl(6947)─┬─sc_serv(6948)─┬─{sc_serv}(6964)
           │               ├─{sc_serv}(6965)
           │               └─{sc_serv}(6966)
           └─sh(6949)─┬─ffmpeg(6950)
                      └─vlc(6952)─┬─{vlc}(6980)
                                  ├─{vlc}(6983)
                                  └─{vlc}(6985)

现在,如果我杀死perl(6947),整个家谱将被正确终止并清理,但是杀死sh(6949)将使其子节点初始化,从而造成一些混乱。

请注意,如果我未将$SIG{CHLD}设置为IGNORE,则sh(6949)会将其子级设为init,并且sh(6949)defunct { {1}}进程。我不明白为什么会这样。所以,

问题1。   为什么在这种情况下我必须将$SIG{CHLD}设置为IGNORE

问题2。   我如何确保如果我需要杀死sh(6949)所有孩子也将被杀死?

我还尝试使用fork以及systemexecfork的结果与使用open的结果非常相似。这是我尝试使用system的子版。

sub start_vlc {

  my $pid = fork();
  if( $pid == 0 ) {
    close STDOUT;
    close STDERR;
    system "(ffmpeg --opt1 --opt2) | vlc --many-options --etc";
  }
  else {
    return $pid;
  }

}

使用此子程序会遇到与上面几乎相同的问题,但现在这些子程序是克隆的perl程序。杀死perl(25991)将使其所有孩子都能够创建与上面相同的混乱。同样杀死所有进程的Parent perl(25982)也不会正确杀死所有子进程。它会杀死一些但不是全部,比我打开的尝试更容易造成混乱。

perl(25982)─┬─perl(25989)───sc_serv(25990)─┬─{sc_serv}(25992)
            │                              ├─{sc_serv}(25993)
            │                              └─{sc_serv}(25994)
            └─perl(25991)───sh(25995)─┬─ffmpeg(25996)
                                      └─vlc(25997)─┬─{vlc}(26042)
                                                   ├─{vlc}(26044)
                                                   └─{vlc}(26046)

问题3。   如何使用fork以及systemexec来生成外部程序并控制其终止而不会将孤儿留给init?

请尽可能详细,我不反对尝试模块,但我宁愿学习如何在没有它们的情况下这样做,以便更好地理解perl的过程控制。

参考:

run process in background without being adopted by init, Perl

How can i get process id of UNIX command i am triggering in a Perl script?

1 个答案:

答案 0 :(得分:2)

Question 1. Why do I have to set $SIG{CHLD} to IGNORE in this situation?

当您进行设置时,它会告诉您的子进程不要闲着,让父母用waitwaitpid来获取。这意味着没有僵尸。重要的是 - 当fork()时,它也会向孩子们级联。因此,您的sh进程正在继承它。

当设置为IGNORE时,sh会在被杀时立即退出,并且孩子会重新显示为init。如果你没有设置它,那么sh将保持僵尸状态,等待父母用wait()收割它并收集返回码。你可能想要这个,因为你的父母可以检测退出条件,并做任何需要清理的事情。

Question 2. How do I make sure that if I need to kill sh(6949) that all of its children will be killed as well?

要么:杀死一个负过程ID,它将向整个树发送相同的信号。或者:使用信号处理程序,并捕获信号 - 如SIGHUPSIGUSR1 - 然后使用该处理程序将信号传播到适当的子进程。 可能是两者的结合。 (见:Best way to kill all child processes

Question 3. How can I use fork along with system or exec to spawn external programs and have control over their termination without leaving orphans to init?

你想避免什么?一个过程所做的所有“重新定位”都意味着init会在他们退出并自动进入僵尸时清理它们。 (您可以通过设置$SIG{'CHLD'}

来避免这种情况

正如评论中提到的那样 - 可能值得看threads而不是fork。它是IPC的另一种模式 - 它可能效率较低,但使某些类型的编程更容易和更清晰 - 特别是任何使用共享内存类型的操作模型。