fork で Bus error
大量のIPアドレスからホスト名を求めたかったのですが、どうも gethostbyaddr が alarmで割り込んでもその通りにならず時間がかかるので、forkして並行処理しようと考えました。で、以下のように書いてみました。
my %working_pids = (); # 子のPIDを格納 local $SIG{CHLD} = sub { my $pid = wait(); delete( $working_pids{$pid} ); }; while( @all_ips ) { #@all_ips にはたくさんのIPアドレスが入っています while( scalar( keys(%working_pids) ) >= $PROCESS_NUM ) { sleep(3); } my @ips = splice( @all_ips, 0, $IP_PAR_PROCESS ); # 子に処理させるもの my $pid = fork(); if ( $pid ) { $working_pids{$pid} = 1; sleep(1); } elsif ( defined( $pid ) ) { # 子プロセス local $SIG{ALRM} = sub { die '__timeout__'; }; foreach my $ipaddr ( @ips ) { next if ( ! $ipaddr ); my $host = ''; eval { alarm( $TIMEOUT ); $host = gethostbyaddr(pack("C4", split(/\./, $ipaddr)), AF_INET); alarm( 0 ); }; alarm( 0 ); if ( $@ ) { print join( "\t", ( $ipaddr, $@, $$ ) ), "\n"; } else { print join( "\t", ( $ipaddr, ($host || ""), $$ ) ), "\n"; } } exit 0; } else { # fork失敗 die "Can't fork."; } }
#上記コード、実際よりは多少はしょっています。
Linux環境(Perl 5.6.1 や 5.8.6)で走らせると問題無いものが、自席のMac OS X Tiger(Perl 5.8.6)だと Bus Error を頻発します。最大の子プロセス数(上記 $PROCESS_NUM)にも依ってくるようなのですが・・・。
Mac OS X の問題でしょうか。それとも、書き方が悪い?ちなみに、gethostbyaddrの行をコメントアウトしても、同じような状況だったので、Mac OS X は fork が安定していないのかな、とか思ってしまったのです・・・。