2009-11-04 58 views
6

這裏是我的代碼,錯誤處理和其他的東西爲清楚起見移除:在Perl中,殺害兒童和它的孩子孩子使用開放創建時

sub launch_and_monitor { 

    my ($script, $timeout) = @_; 

    sub REAPER { 
     while ((my $child = waitpid(-1, &WNOHANG)) > 0) {} 
     $SIG{CHLD} = \&REAPER; 
    } 
    $SIG{CHLD} = \&REAPER; 

    my $pid = fork; 
    if (defined $pid) { 
     if ($pid == 0) { 
      # in child 
      monitor($timeout); 
     } 
     else { 
      launch($script); 
     } 
    } 
} 

推出子執行shell腳本,啓動其他過程,像這樣:

sub launch($) { 

    my ($script) = @_; 

    my $pid = open(PIPE, "$script|"); 

    # write pid to pidfile 

    if ($pid != 0) { 
     while(<PIPE>) { 
      # do stuff with output 
     } 
     close(PIPE) or die $!; 
    } 
} 

監視器子基本上只是等待指定的時間週期,然後嘗試殺外殼腳本。

sub monitor($) { 

    my ($timeout) = @_; 

    sleep $timeout; 

    # check if script is still running and if so get pid from pidfile 
    if (...) { 
     my $pid = getpid(...);   
     kill 9, $pid; 
    } 
} 

這會殺死腳本,但是它不會殺死它的任何子進程。怎麼修?

+0

我沒有回答你的主要問題,但我會建議做'REAPER'匿名子,例如'我的$ reaper = sub {...}; $ SIG {CHLD} = $ reaper;'將一個名爲sub的子文件放入另一個子文件夾中並不會將其隱藏在其他作用域中。所有指定的subs都是Perl中的包號符號 – friedo 2009-11-04 18:39:39

+0

http://www.speculation.org/garrick/kill-9.html – 2009-11-04 19:21:18

+0

好點,謝謝指出 – richard 2009-11-04 19:36:16

回答

12

你可以用進程組做到這一點,如果您的操作系統支持他們。你需要使腳本程序成爲進程組創建者。子進程,這將運行從其父繼承進程組。然後,可以使用殺來的信號在同一時間發送到每個進程在一組。

launch()中,您需要將open行替換爲分叉。然後在孩子,你會exec'ing命令之前調用setpgrp()。像下面這樣的東西應該工作:

my $pid = open(PIPE, "-|"); 
if (0 == $pid) { 
    setpgrp(0, 0); 
    exec $script; 
    die "exec failed: $!\n"; 
} 
else { 
    while(<PIPE>) { 
     # do stuff with output 
    } 
    close(PIPE) or die $!; 
} 

後來,殺死腳本進程和它的孩子,否定,你信令進程ID:

kill 9, -$pid; 
+0

我認爲你應該否定信號編號(或名稱)而不是PID:'kill'-9',$ pid'。 – jreisinger 2015-08-26 12:09:08

2

一般來說,我不認爲你可以期望信號傳播到所有的子進程;這不是特定於perl的。

這就是說,你可能能夠使用信號的功能內置到perl的kill()過程:

...如果信號爲負,它殺死進程組,而不是流程...

你可能需要在你的(直接)子過程中使用setpgrp(),然後改變你殺調用是這樣的:

kill -9, $pgrp; 
2

嘗試增加:

use POSIX qw(setsid); 
setsid; 

launch_and_monitor函數的頂部。這將使你的流程在一個單獨的會話,並導致東西離開時,會議領導(即主)退出。

0

殺滅processgroup作品,但不要」 t忘記父母也可以單獨被殺害。假設子進程有一個事件循環,他們可以在執行fork()以驗證有效性之前檢查在套接字對中創建的父套接字。事實上,當父套接字不存在時,select()乾淨地退出,所有需要做的就是檢查套接字。

E.g.:

use strict; use warnings; 
use Socket; 

$SIG{CHLD} = sub {}; 

socketpair(my $p, my $c, AF_UNIX, SOCK_STREAM, PF_UNSPEC) or die $!; 

print "parent $$, fork 2 kids\n"; 
for (0..1){ 
    my $kid = fork(); 
    unless($kid){ 
     child_loop($p, $c); 
     exit; 
    } 
    print "parent $$, forked kid $kid\n"; 
} 

print "parent $$, waiting 5s\n"; 
sleep 5; 
print "parent $$ exit, closing sockets\n"; 

sub child_loop { 
    my ($p_s, $c_s) = @_; 
    print "kid: $$\n"; 
    close($c_s); 
    my $rin = ''; 
    vec($rin, fileno($p_s), 1) = 1; 
    while(1){ 
     select my $rout = $rin, undef, undef, undef; 
     if(vec($rout, fileno($p_s), 1)){ 
      print "kid: $$, parent gone, exiting\n"; 
      last; 
     } 
    } 
} 

運行像這樣:

[email protected]:~$ perl ~/abc.pl 
parent 5638, fork 2 kids 
parent 5638, forked kid 5639 
kid: 5639 
parent 5638, forked kid 5640 
parent 5638, waiting 5s 
kid: 5640 
parent 5638 exit, closing sockets 
kid: 5640, parent gone, exiting 
kid: 5639, parent gone, exiting 
[email protected]:~$ 
相關問題