0

AnyEvent と EV を使用していくつかのコードを実装しようとしています。チャイルドウォッチャーをインストールしたい(以下のやりたいことのモックアップ)

use Modern::Perl;
use AnyEvent;
use EV;

my $SIG{QUIT} = \&kill_child;
my $exit_status = undef;
my $pid = fork or exec 'child.pl';
my $w = AnyEvent->child(pid => $pid, cb => sub { $exit_status = $_[2]; cleanup_after_child(); });
my $t = AE::timer 0, 5, sub { say $exit_status; fork_another_process(); };

AnyEvent->condvar->recv;

sub kill_child{
    foreach my $signal (qw(HUP QUIT INT KILL)){
        if(child_alive()){
            kill($signal,$pid);
            sleep 1;
        }
    }
    exit; #Probably wrong
}

child_alive() の作成と、さまざまなコールバックのタイミングの把握、および kill_child() での終了の配置について、助けが必要です。プロセスが終了する前に cleanup_after_child() が呼び出されるようにする必要があります。

AnyEvent Signal ウォッチャーを使用すると役立ちますか? 私の目標は、最初にプロセスの子プロセスを強制終了し、その後クリーンアップすることで、デーモン プロセスを安全にシャットダウンできるようにすることです。以前に関連する質問 ( perl での子プロセスの待機中) を行いましたが、終了処理中にそのバグが発生するのを防ぎたいと考えています。

ありがとう

編集: child_alive() 関数に対して次のように機能しますか?

sub child_alive{
    return defined($exit_status)?1:0;
}

言い換えれば、コールバックは子が終了するとすでに呼び出されているのでしょうか、それともコールバックは EventLoop の次の繰り返しでのみ実行されるのでしょうか? もしそうなら、すべてのシグナルが処理された後にのみ終了するにはどうすればよいですか? 次のようなすべてのイベントを削除するだけですか。

$w = undef;
$t = undef;

申し訳ありませんが、信号が一般的にどのように機能するかよりも、AnyEvent がこれらの信号をどのように処理するかを理解しようとしています。

4

2 に答える 2

5

You can use a hash to keep track of the children you have.

$children{$pid} = 1;       # On creation.

delete($children{$pid});   # On reaping.

keys(%children)            # Lists existing children.

So all that's left is waiting for all the children to complete, and there's already an example of that in AnyEvent->child's documentation.

All together, we get

my $done = AnyEvent->condvar;
my %children;
my $spawner;

sub ae_sleep {
   my ($dur) = @_;
   my $done = AnyEvent->condvar;
   my $t = AnyEvent->timer(after => $dur, cb => sub { $done->send });
   $done->recv;
}

sub kill_children {
   for my $sig (qw( HUP QUIT INT KILL )) {
      last if !%children;
      kill($sig => $_) for keys(%children);
      ae_sleep(1);
   }
}

$SIG{QUIT} = sub {
   $spawner = undef;   # Stop creating new children.
   kill_children();    # Kill existing children.
   $done->recv;        # Wait for children to be reaped.
   exit(0);
}

sub create_child {
   my $pid = ...;
   $done->begin;
   $children{$pid} = AnyEvent->child(
      pid => $pid,
      cb  => sub {
         my ($pid, $status) = @_;
         delete($children{$pid});
         warn "pid $pid exited with status $status";
         $done->end;
      },
   );
}

$spawner = AnyEvent->timer(
   after    => 0,
   interval => 5,
   cb       => \&create_child.
);

AnyEvent->condvar->recv; # Wait "for ever".
于 2013-09-16T16:56:30.663 に答える
1

からperldoc -f kill:

SIGNAL が数値 0 または文字列 "ZERO" (または "SIGZZERO") の場合、プロセスにシグナルは送信されませんが、"kill" はプロセスにシグナルを送信できるかどうかをチェックします (つまり、簡単に言うと、プロセスが同じユーザーによって所有されているか、スーパーユーザーであること)。これは、子プロセスがまだ生きていて (ゾンビとしてのみであっても)、その UID が変更されていないことを確認するのに役立ちます。この構文の移植性に関する注意事項については、perlport を参照してください。

于 2013-09-16T16:22:34.680 に答える