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


Автор: Trewsa 24.5.2012, 10:24
Дбрый день! Написал небольшой скрипт для сбора логов с локальных серверов. Использовал среду cyqwin(perl5.10) для написания и отладки. В скрипте встречаются вызовы fork(), также использование eval и все отлично работает, но когда я поатылся запустить окружении strawberry perl или в activestate, то ни вызов fork не работает и заврешается программа в eval блоке.       
Вот вызов fork, который отлично работает в cygwin и не выполняется в activestate и strawberry. 
Код

for (@table_hosts) {
   my $pid = fork();
   die "fork cannt started: $!" unless defined $pid;
   unless ( $pid ) {
        print"Connect to $_  ";
                my $ftp=Net::FTP->new($_) or die "Can't connect: $@\n";
                $ftp->login($user,$password) or die $ftp->message;
                mkdir "data/$_"
                $ftp->get($rfile, "data/$_/report.txt");
                $ftp->quit;
            print"Complete connect\n"; 
       exit( 0 );
   }  
} 

 А этот фрагмент c eval{}, который тоже не выполняется в   в activestate и strawberry, т.е. если встречается исключение, то  останов всего скрипта.

Код

eval {
$host = new Net::Telnet (Timeout => 10,Prompt => '/[%#>] $/');
$host->open($hostname);
$host->login($username, $passwd);
};
if ($@) {
    print"So so sorry, $hostname\t$@\n";
    delete($table_h{$hostname});
    return
}



Кто сталкивался с такими проблемами? Возможно ли, что это разница версий perl(5.10 и 5.14)? Как можно это исправить? Спасибо!






Автор: Pfailed 24.5.2012, 11:46
Думаю это связано с тем, что в Windows отстутствует системный вызов fork(): http://perldoc.perl.org/perlfork.html

Автор: Trewsa 24.5.2012, 12:03
Цитата(Pfailed @ 24.5.2012,  11:46)
Думаю это связано с тем, что в Windows отстутствует системный вызов fork(): http://perldoc.perl.org/perlfork.html

Да, действительно. В  cygwin  это же побольшому счету  реализация совместимости стандарта POSIX  и   вызов fork() присутствует. 
Цитата

cygwin1.dll, которая обеспечивает совместимость API и реализует значительную часть стандарта POSIX и огромная коллекция приложений, которые обеспечивают привычную среду UNIX. 

Спасибо за подсказку с perlfork(). Теперь надо добавить корректную проверку окружения.  С  блоком eval{} скорее всего таже проблема, какое нибудь windows исключение, которое не отлавливается. 
 


Автор: DurRandir 24.5.2012, 13:13
>perl -e "print defined fork()?($$, qq!\n!):0"
15844
-18364

>perl -V
Summary of my perl5 (revision 5 version 10 subversion 1) configuration:

  Platform:
    osname=MSWin32, osvers=5.1, archname=MSWin32-x86-multi-thread
    uname='Win32 strawberryperl 5.10.1.2 #1 Wed Apr 28 11:51:06 2010 i386'

Так что проблема у вас не в форке (да, форк на win* имеет проблемы, но они одинаковы для _любого_ билда). Если вы не можете отловить ошибку eval'ом (скорее всего, она выскакивает не там, где вы её ожидаете), то повесьте обработчик на $SIG{__DIE__} с выводом стектрейса. Автоматически это поможет сделать Carp::Always. 

PS: у меня есть одно предположение - т.к. в винде fork - это, на самом деле, cоздание нового потока, то у вас могут быть использованы потоконебезопасные модули. Они то и падают, где-нибудь внутри XS.

Автор: Trewsa 25.5.2012, 08:24
Цитата(DurRandir @ 24.5.2012,  13:13)

Так что проблема у вас не в форке (да, форк на win* имеет проблемы, но они одинаковы для _любого_ билда). Если вы не можете отловить ошибку eval'ом (скорее всего, она выскакивает не там, где вы её ожидаете), то повесьте обработчик на $SIG{__DIE__} с выводом стектрейса. Автоматически это поможет сделать Carp::Always. 

PS: у меня есть одно предположение - т.к. в винде fork - это, на самом деле, cоздание нового потока, то у вас могут быть использованы потоконебезопасные модули. Они то и падают, где-нибудь внутри XS.

Проверил у себя
Код

C:\>perl -e "print defined fork()?($$, qq!\n!):0"
2040
-3944

на конфигурации 
  
Код

Platform:
    osname=MSWin32, osvers=5.2, archname=MSWin32-x86-multi-thread
    uname=''
    config_args='undef'


А после несколько учебных fork-ов запустил. Вы оказались правы, проблема не в форке. Проблема оказалась

Код

my $net=Net::Ping->new('syn');
$net->hires();
foreach  (@hosts) {
    $net->ping($_);  # именно здесь не выполняется код в Activestate и Strawberry
}
while ((my $host_local, my $rtt)=$net->ack()) {
     $table_h{$host_local}=$rtt;     # и тут собственно хеш пуст
        print"$host_local\t$rtt\n"; 
}
print "Complete!\n";
}  


Автор: DurRandir 25.5.2012, 16:00
1) Посмотрите баги Net::Ping - там много веселого, в несколько потоков (форков под win*) его использовать не получится.
2) Запускайте от имени администратора - обычный пользователь не может создавать raw-сокеты.
3) Посмотрите на AnyEvent::Ping, если надо распараллелить поток запросов. Да и вообще всю сеть лучше писать на AnyEvent. Но замечание из п.2 тут тоже в силе.

Автор: Trewsa 28.5.2012, 09:34
Цитата(DurRandir @ 25.5.2012,  16:00)
2) Запускайте от имени администратора - обычный пользователь не может создавать raw-сокеты.
3) Посмотрите на AnyEvent::Ping, если надо распараллелить поток запросов. Да и вообще всю сеть лучше писать на AnyEvent. Но замечание из п.2 тут тоже в силе.

И от пользователя с админ. правами, такая же ситуация, в cygwin работает отлично, в activeperl не выполняется. Начал изучать AnyEvent, попробую переделать с его использованием, жаль что документации  по нему мало. Возник другой вопрос, а есть ли модули для просмтора(опроса) сети, просто подумалось, что поиск станций  таким методом  foreach  (@hosts) {$net->ping($_);} не очень корректно. 

Автор: arto 28.5.2012, 14:25
на какой предмет вы хотите опрашивать?
icmp echo может быть запрешен на роутере.

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