2012-03-22 57 views
2

我有一个用Perl编写的使用Inotify2观察传入文件的目录的守护进程。每个文件到达后,守护进程将分叉一个子进程。现在,似乎太多的文件正在到达的同时(因此太多叉),因为我在日志文件中得到这个错误:在perl中分页文件系统事件的子进程

Cannot allocate memory at notifyd.pl line ... 

这是叉()的结果。

基本上我有以下代码:

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($!); 
    } 

与守望功能做叉,然后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($!); 
     } 
} 

我不能用不派生进程错过的事件。

有没有人有建议如何我可以改善这一点,并确保叉不会失败?


编辑:它看起来像子进程变成僵尸一旦他们退出,因为守护进程不会响应SIGCHLD。所以很多僵尸子进程可能是fork()失败的原因。守护进程现在在分叉之前执行$SIG{CHLD} = 'IGNORE';

+1

如果您有很多文件更改,则耗尽资源相当容易,并且根据您的使用情况,它是dos攻击的一个向量。您应该使用cpan上的某个事件循环来处理这些事件。一个好的起点可能是看AnyEvent。 – 2012-03-22 15:35:29

+0

你确定fork()失败吗?您(部分)存在的错误消息看起来像是来自'die'或'warn',但是如果fork失败(即,如果$ pid未定义),则显示的代码将不会生成该输出。 – pilcrow 2012-03-22 15:50:24

+0

是的,消息来自这部分代码: if(!defined $ pid){print“[ERROR]”,$ !; } – 2012-03-22 15:53:15

回答

2

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

当您收到一个事件时,将文件名称放入job queue。当资源合理时,队列开始处理文件的新作业;该方案保证该事件最终将被采取行动,而不是立即全部采取行动。

+0

谢谢,我需要研究实现它的可能方式。事情是我真的不想有另一个进程只是为了处理队列。 – 2012-03-22 16:00:16

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($!); 
     } 
    }; 
} 
+0

谢谢。这看起来不错,除非我可能无法安装该模块,所以我必须自己实现类似的东西。 – 2012-03-22 15:54:51