4

Linux ホストで perl スクリプトを実行しています。分岐するスクリプトを作成しようとしています。このプログラムでは、子が永遠にかかるプログラムを開始し、親が 5 秒後にタイムアウトして子を殺します。ここに私が持っているものがあります:

my $start = time();
my $timeOut = 5;

my $childPid = fork();
if ($childPid) {
    # I am the parent, and $childPid is my child
    while (kill(0, $childPid)) {
        if (time() > $start + $timeOut) {
            $numKilled = kill(SIGTERM, $childPid);
            printf("numKilled: %s\n", $numKilled);
        }
        sleep 1;
    }
}
else {
    # I am the child - do something that blocks forever
    `adb -s 410bf6c1 logcat`;
    exit;
}

出力:

aschirma@graphics9-lnx:~$ perl perl-fork-test.pl 
numKilled: 1
numKilled: 1
numKilled: 1
numKilled: 1
numKilled: 1
...

私が期待する動作は、「numKilled: 1」が 1 回だけ表示され、子プロセス (およびそのすべての子プロセス) が約 5 秒後に強制終了されることです。しかし、実験から、子供もその子供も殺されていないことがわかります。はkill(SIGTERM, $childPid)何もしていないように見えます。

どうすれば実際に子供を殺すことができますか?

4

6 に答える 6

6

このようなものでなければなりません。これはベストプラクティスに従っていませんが、問題の解決に役立つはずです...

#!/usr/bin/perl

use warnings;
use strict;
use POSIX qw(:sys_wait_h);

my $timeOut = 5;
$SIG{ALRM} = \&timeout;
$SIG{CHLD} = 'IGNORE',
alarm($timeOut);

my $childPid = fork();
if ($childPid) {
    while(1) {
        print "[$$]: parent...\n"; 
        sleep(2); 
    }
}else {
    # I am the child - do something that blocks forever
    while(1){
        print "[$$]: child...\n";
        sleep(2);
    }
    exit;
}

sub timeout {
    print "killing $childPid\n";
    print "###\n" . `ps -ef | grep -v grep | grep perl` . "###\n";
    if ( ! (waitpid($childPid, WNOHANG)) ) {
        print "killing $childPid...\n";
        kill 9, $childPid;
        die "[$$]: exiting\n";
    }
}

出力:

$ forktest.pl
[24118]: parent...
[24119]: child...
[24118]: parent...
[24119]: child...
[24118]: parent...
[24119]: child...
killing 24119
###
cblack   24118 12548  0 14:12 pts/8    00:00:00 /usr/bin/perl ./forktest.pl
cblack   24119 24118  0 14:12 pts/8    00:00:00 /usr/bin/perl ./forktest.pl
###
killing 24119...
[24118]: exiting
于 2013-02-21T22:13:43.027 に答える
4

perldoc forkから:

子供たちを待たずに分岐すると、ゾンビが蓄積します。一部のシステムでは、 $SIG{CHLD} を "IGNORE" に設定することでこれを回避できます。

$SIG{CHLD} = 'IGNORE';コードの先頭に追加すると、目的の動作を得ることができました。

[ben@imac ~]$ perl test.pl
numKilled: 1
[ben@imac ~]$ 

waitpid($childPid, 0);または、後に追加することkillも同様にうまくいきました。

于 2013-02-21T21:58:07.377 に答える
1

プロセスグループを強制終了してみてください(-$ pidを使用):

kill TERM => -$pid;

perlipcを参照してください。

于 2013-02-22T01:05:07.527 に答える
1

スクリプト内でも ing でもない可能性があるため、usestrictベアワードとして解釈され、有用な方法で動作していません。POSIXSIGTERM"SIGTERM"

use strictこの偶発的な裸の単語をエラーにしてから、定数use POSIXを引き込みます。SIGTERM

于 2013-02-21T21:28:39.837 に答える
1

プロセスが終了した後でも kill 0 が true を返すというこの動作も見ています。この結果となる waitpid (多くの場合、SIGCHLD ハンドラーで行われる) の呼び出しが欠落している可能性があるのではないかと思いましたが、追加した後でも、kill 0 は引き続き true を返します。

kill の代わりにノンブロッキングの waitpid を使用することをお勧めします (そして、プロセスが実際に SIGTERM シグナルで終了することを確認します - いくつかは、少なくともすぐには終了しないかもしれません)。SIGTERM が機能しない場合は、しばらくしてから SIGINT を試して、最後の手段として SIGKILL を試すこともできます。

于 2013-02-21T21:46:23.487 に答える