在perl中对子文件系统事件上的子进程进行分叉

时间:2012-03-22 15:24:07

标签: perl filesystems fork inotify

我有一个用Perl编写的守护进程,它使用Inotify2来监视传入文件的目录。在每个文件到达时,守护进程将分叉一个子进程。现在,似乎有太多文件同时到达(因此太多的分叉),因为我的日志文件中出现了这个错误:

Cannot allocate memory at notifyd.pl line ...

这是fork()的结果。

基本上我有以下代码:

    my $inotify = new Linux::Inotify2() or die($!);

    foreach my $k (@PATHS) {
        $inotify->watch($k,
IN_MOVE_SELF|IN_DELETE_SELF|IN_CLOSE_WRITE, \&watcher) or die($!);
    }

    $inotify->blocking(1) or die($!);

    for(;;) {
        $inotify->poll() or die($!);
    }

使用watcher函数执行fork然后执行execv:

sub watcher {
        my $e = shift;
        my $pid = fork();
        if(!defined $pid) {
            print "[ERROR]", $!;
        }
        elsif($pid == 0) {
            my @args = ($e->fullname, $e->mask);
            exec($childprocess, @args) or die($!);
        }
}

我不能错过任何过程。

有没有人建议我如何改进这一点并确保fork不会失败?


编辑:由于守护程序不会响应SIGCHLD,因此子进程一旦退出就会变成僵尸。因此很多僵尸子进程可能是fork()失败的原因。在分叉之前守护进程现在$SIG{CHLD} = 'IGNORE';

2 个答案:

答案 0 :(得分:2)

通过添加另一层间接来解决问题。

收到活动后,请将文件名放入job queue。当资源合理免费时,队列开始处理文件的新作业;这个方案保证事件最终会被采取行动,而不是立即采取行动。

答案 1 :(得分:2)

使用更强大的后台流程管理器,例如Forks::Super

例如,此设置一次最多可运行10个货叉。当所有10个叉子都忙时进入的新请求将被放入队列中。队列中的作业将在其他后台进程完成且资源可用时运行。

use Forks::Super  MAX_PROC => 10, ON_BUSY => 'queue';

...

sub watcher {
    my $e = shift;
    fork {
       sub => sub {
           my @args = ($e->fullname, $e->mask);
           exec($childprocess, @args) or die($!);
       }
    };
}