Форкирование дочерних процессов в событиях файловой системы в perl - PullRequest
2 голосов
/ 22 марта 2012

У меня есть демон-процесс, написанный на 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($!);
    }

с функцией наблюдателя, выполняющей 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 ]

2 голосов
/ 22 марта 2012

Используйте более надежный менеджер фоновых процессов, такой как 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($!);
       }
    };
}
2 голосов
/ 22 марта 2012

Решите проблему, добавив еще один слой косвенности.

При получении события поместите имя файла в очередь заданий .Очередь начинает новое задание, обрабатывающее файл, когда ресурсы свободны;эта схема гарантирует, что событие в конечном итоге будет выполнено, но не все сразу.

...