LINUX.ORG.RU

perl наследование от потока


0

0

Хочу сделать свой perl класс, который бы наследовывал бы поведение класса threads.

Задача такая, надо одновременно читать logi с нескольких файлов,
я думаю создать 1 класс log_reader и потом для каждого нового файла запускать его в отдельном потоке,
но у меня эта затея не получается, не поможете примером или советом?

★★

форкнись на число процессов, равное числу логов, на кажудый сделай tail -f при помощи File::Tail и радуйся жизни.

vilfred ☆☆
()
Ответ на: комментарий от vilfred

Вот ниже прога, которая читает и выводит на печать все, что 
пишется в системные логи, находящиеся в определенной директории.

#!/usr/bin/perl -w

use strict;
use POSIX;
use File::Find;
use File::Tail;
# подсчет числа логов
my $count=0;
# системные переменные
my (%h,$fi,$l);
# директория, где лежат логи
my $dir='/var/log';

# вызов подпрограммы, которая рекурсивно читает все вложенные 
# директории с логфайлами 
find \&read_files, $dir;

my $PREFORK=$count++; 
my %children=(); 
my $children=1;
# плодим потомка, который читает определенные логи
# на каждого потомка определенный логфайл
make_new_child($_) for(1 .. $PREFORK);
#работа с чайлд-процессами
$SIG{CHLD}=\&REAPER; 
$SIG{INT}=\&HUNTSMAN;

# если потомок умер - перезапустить(что оно будет читать - не знаю, 
# это долго писать)
while(1){ 
  sleep; my $i;
  make_new_child($i) for $i=$children; $i<$PREFORK; $i++;
}
# плодим потомка
sub make_new_child{ 
  my $fnh=$_[0];
# переменная $fnh содержит цифру, которая в хеше %h соответствует 
# имени логфайла
  my($pid, $sigset, $kidpid, $server, $client);
# работа с сигналами
  $sigset=POSIX::SigSet->new(SIGINT);
# блокировка SIGINT
  sigprocmask(SIG_BLOCK, $sigset) or die "can't block SIGINT for fork: $!\n";
  die "fork: $!" unless defined do{$pid = fork};

  if($pid){
    sigprocmask(SIG_UNBLOCK, $sigset) 
      or die "can't unblock SIGINT for fork: $!\n";
# если чайлд запущен, заполняется хеш с процессами, 
# которые должны умирать по завершении того или иного чайда
    $children{$pid}=1; 
    $children++; 
    return;
  } else {
# тело самого чайда, предыдущий - парент, потому работа с логом
# находится в этом условии(это условие и будет чайлдом)
# заодно переопределим сигналы
    $SIG{INT} = 'DEFAULT'; 
    $SIG{CHLD}='IGNORE';

    sigprocmask(SIG_UNBLOCK, $sigset) 
      or die "can't unblock SIGINT for fork: $!\n";
#    print "$fnh => $h{$fnh}\n";
# вызываем чтение необходимого лога в необходимом процессе 
# (соответствие необходимого процесса с необходимым файлом и с
# и каким по счету процессом будет процесс читающий данный лог
# находится в хеше %h )
# по аналогии с системной командой tail -f
    &tail_socket($h{$fnh});
    while(1){
      print "\n from process $$ (filename $fnh)\n $_" while($_=$fi->read);
    }
    exit;
# этот выход ОБЯЗАТЕЛЕН, иначе будет непрерывный форк и 
# системная таблица процессов забъется чайлд-процессами!
  }
}

sub HUNTSMAN{
# убийство чайлда, выше при паренте для  исключения зомби стоит waitpid
  local($SIG{CHLD})='IGNORE';
  kill 'INT' => keys %children;
  exit;
}

sub REAPER{
# переобработка SIGGLD
  $SIG{CHLD}=\&REAPER;
  my $pid = wait;
  $children--;
  delete $children{$pid};
}
sub read_files { 
# чтение всех логов и заполнение хеша с именами файлов
  do{
    $h{$count}=$File::Find::name if -f $File::Find::name; 
    $count++ if -f $File::Find::name;
  } unless /\.(\d+)$/
}
sub tail_socket{
# чтение текущего по вызову лога, т.е. вывод на печать 
# в чалде того, что добавляется в логфайл
  return $fi = File::Tail->new(
                                 name => $_[0],
                          maxinterval => 0.1,
                          adjustafter => 1000000000,
                             interval => 4,
                                 tail => 0)
}


p.s. интересно, сколько строк займет программа аналогичной 
функциональности на C(++) или какомннить другом языке?

vilfred ☆☆
()
Ответ на: комментарий от vilfred

короче, апач, сендмыл и messages оно выводид... если че не так, ща врядли че напишу, т.к. поллитры дают себя знать... завтра или послезавтра.

vilfred ☆☆
()
Ответ на: комментарий от vilfred

> Вот ниже прога, которая читает и выводит на печать все, что
> пишется в системные логи, находящиеся в определенной директории.

все как-то излишне усложнено.

> my $children = 1;

зачем нужна эта переменная? количество потомков
можно получить как 0+%children

да и %children не нужен, просто делайте
kill INT => 0 в HUNTSMAN. и sigblock не нужен
тогда.

да и REAPER не нужен, просто SIG{CHLD} = 'IGNORE'

> make_new_child($i) for $i = $children; $i < $PREFORK; $i++;

это не будет работать. да и вообще у вас:

make_childs;
while(1) {
       sleep;
       make_childs;
}

что эквивалентно

while(1) {
       make_childs;
       sleep;
}

дальше не читал

idle ★★★★★
()
Ответ на: комментарий от vilfred

> просветление

ну а вы бы помогли мне просветиться, указали бы
в чем конкретно я не прав (вполне допускаю, что
это имело место быть).

vilfred, не напрягайтесь и не хамите, пожалуйста.

если я и критиковал ваш код, то абсолютно без
желания наехать. если вас это так задевает, зачем
было его здесь публиковать?

idle ★★★★★
()
Ответ на: комментарий от idle

блин, прошу прощения за наезды... я думал это очередной Луговский. Короче так, этого кода слямзено отсюда: http://home.dti.ru/oreilly/books/perl2/cookbook/ch17_13.htm фишка там в том, что это наиболее общий вариант, который учитывает блокировку сигналов ( http://home.dti.ru/oreilly/books/perl2/cookbook/ch16_21.htm )

т.е. у меня это ядро много где работает не только как форк чайлдсерверов. Там можно реально удивительные вещи делать типа нафоркать парутройку чайлдов и между клиентами общаться. Это просто универсальное решение.

Я просто изменил код (приведенный в первой ссылке) немного и все. прошу ее раз прощения за наезд.

vilfred ☆☆
()
Ответ на: комментарий от idle

это решение вобщем на случай атомного взрыва, скажем так. универсальная штука вобщем... тут года назад был тред. где мужику надо было парсить лог апача так, чтобы запись для определенного ip-адреса шла на определенный порт. эта конструкция - помогла вроде бы. Хотя я не скрою, я месяца три разбирался с перловскими сигналами, не буду говорить, что до конца разобрался...

еще раз извиняюсь

vilfred ☆☆
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.