Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Perl: Общие вопросы > fork, системные вызовы и kill


Автор: cerberon 29.6.2010, 16:37
Есть код, который порождает child'ов, которые в свою очередь вызывают команду через system/exec/``. Родитель в некоторый момент убивает потомков, при этом вызванная команда продолжает работать, что не есть хорошо.
Ближе к коду, задача скрипта: считать урлы из файла и запустить рекурсивную скачку wget'ом, по достижении лимита загруженных страниц - прервать закачку, сам код (извиняюсь за комменты в С-стиле, решетку ставить неудобно):
Код

my $file=$ARGV[0]; //в качестве аргумента получаем файл со списком урлов

open URLS, "<$file" or terminate("Can't open URL file $file: $!");

my @threads=();

while (my $url=<URLS>)
{
    chomp $url;
    next if $url=~/^#/;

    my $sitename;
    $sitename=($url=~/^http:\/\/([^\/]+)/)?$1:$url;
    mkdir "$cfg{save_dir}/$sitename" or terminate("Can't create directory $cfg{save_dir}/$sitename") if !(-d "$cfg{save_dir}/$sitename");

    while(scalar @threads>=$cfg{thread}) //если превышен лимит потомков, проверяем потомки на предмет возможности их завершения
    {
        check_thread();
        sleep(1);
    }
    my @files=`find $cfg{save_dir}/$sitename -type f`; //ищем загруженные файлы
    if (scalar @files<$cfg{limit}) 
    {
        my $th=fork();  //порождаем потомка если лимит страниц не достигнут
        if ($th==0)
        {
            start_wget($url); //в потомке запускаем wget
            exit(1);
        }
        elsif (!defined($th))
        {
            terminate("Can't fork child: $!");
        }
        else
        {
            push @threads,[$th,$sitename]; //в родителе сохраняем pid 
        }
    }
}

while (scalar(@threads)) //пока есть живой потомок, проверяем
{
    check_thread();
    sleep(1);         
}

exit(0);

sub start_wget
{
    my $url=shift;
    my $sitename;
    $sitename=($url=~/^http:\/\/([^\/]+)/)?$1:$url;
    $url='http://'.$url if $url!~/^http/;
    system("wget","$url","-nv","-nc","-np","-nH","-rl0","-t5","$cfg{wget}","-P$cfg{save_dir}/$sitename"); 
}

sub check_thread
{
    for (my $i=0; $i<scalar @threads;++$i) 
    {
        my $sitename=$threads[$i]->[1];
        my @files=`find $cfg{save_dir}/$sitename -type f`;
        my $nfiles=scalar(@files);
        debug("Download $nfiles files");
        if ($nfiles>=$cfg{limit}||!(kill 0,$threads[$i]->[0])) //проверяем завершились ли потомки, или достигли лимита загруженных страниц
        {
            debug("Downloading $sitename finished with $nfiles files");
            kill TERM => $threads[$i]->[0]; //убиваем 
            splice(@threads,$i,1);
            $i--;        
        }        
    }
}

В итоге имеем, что потомок убит, родитель завершился, а wget продолжает закачку. Пробовал и обратные кавычки, результат тот же.

Автор: cerberon 30.6.2010, 12:08
пока ничего лучше:
Код

my $ps=`ps -ef | awk '{print \$2,\$3}' | grep ' $threads[$i]->[0]'`;
my $wget_pid=(split ' ',$ps)[0];
kill TERM => $wget_pid if defined $wget_pid;

не придумалось, но хоть работает

Автор: DurRandir 30.6.2010, 17:42
perldoc -f exec

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)