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