2013-05-09 114 views
0

看來在線程中使用管道可能會導致線程變成殭屍。事實上,管道中的命令被轉化爲殭屍,而不是線程。這不會發生很煩人的時間,因爲很難找出真正的問題。如何處理這個問題?是什麼導致這些?它與管道有關嗎?如何避免這種情況?如何處理perl中變成殭屍的多線程

以下是創建示例文件的代碼。

#buildTest.pl 
use strict; 
use warnings; 

sub generateChrs{ 
    my ($outfile, $num, $range)[email protected]_; 
    open OUTPUT, "|gzip>$outfile"; 
    my @set=('A','T','C','G'); 
    my $cnt=0; 
    while ($cnt<$num) { 
     # body... 
     my $pos=int(rand($range)); 
     my $str = join '' => map $set[rand @set], 1 .. rand(200)+1; 
     print OUTPUT "$cnt\t$pos\t$str\n"; 
     $cnt++ 
    } 
    close OUTPUT; 
} 

sub new_chr{ 
    my @chrs=1..22; 
    push @chrs,("X","Y","M", "Other"); 
    return @chrs; 
} 

for my $chr (&new_chr){ 
    generateChrs("$chr.gz",50000,100000) 
} 

以下代碼會偶爾創建殭屍線程。原因或觸發因素仍然未知。

#paralRM.pl 
use strict; 
use threads; 
use Thread::Semaphore; 
my $s = Thread::Semaphore->new(10); 

sub rmDup{ 
    my $reads_chr=$_[0]; 
    print "remove duplication $reads_chr START TIME: ",`date`; 
    return 0 if(!-s $reads_chr); 

    my $dup_removed_file=$reads_chr . ".rm.gz"; 
    $s->down(); 
    open READCHR, "gunzip -c $reads_chr |sort -n -k2 |" or die "Error: cannot open $reads_chr"; 
    open OUTPUT, "|sort -k4 -n|gzip>$dup_removed_file"; 

    my ($last_id, $last_pos, $last_reads)=split('\t',<READCHR>); 
    chomp($last_reads); 
    my $last_length=length($last_reads); 
    my $removalCnts=0; 

    while (<READCHR>) { 
     chomp; 
     my @line=split('\t',$_); 
     my ($id, $pos, $reads)[email protected]; 
     my $cur_length=length($reads); 
     if($last_pos==$pos){ 
      #may dup 
      if($cur_length>$last_length){ 
       ($last_id, $last_pos, $last_reads)[email protected]; 
       $last_length=$cur_length; 
      } 
      $removalCnts++; 
      next; 
     }else{ 
      #not dup 
     } 
     print OUTPUT join("\t",$last_id, $last_pos, $last_reads, $last_length, "\n"); 
     ($last_id, $last_pos, $last_reads)[email protected]; 
     $last_length=$cur_length; 
    } 

    print OUTPUT join("\t",$last_id, $last_pos, $last_reads, $last_length, "\n"); 
    close OUTPUT; 
    close READCHR; 
    $s->up(); 
    print "remove duplication $reads_chr END TIME: ",`date`; 
    #unlink("$reads_chr") 
    return $removalCnts; 
} 


sub parallelRMdup{ 
    my @[email protected]_; 
    my %jobs; 
    my @removedCnts; 
    my @processing; 

    foreach my $chr(@chrs){ 
     while (${$s}<=0) { 
      # body... 
      sleep 10; 
     } 
     $jobs{$chr}=async { 
      return &rmDup("$chr.gz") 
      } 
     push @processing, $chr; 
    }; 

    #wait for all threads finish 
    foreach my $chr(@processing){ 
     push @removedCnts, $jobs{$chr}->join(); 
    } 
} 

sub new_chr{ 
    my @chrs=1..22; 
    push @chrs,("X","Y","M", "Other"); 
    return @chrs; 
} 

&parallelRMdup(&new_chr); 
+1

是否所有的線程都報告了合理的開始和結束時間?但是我看不到任何明顯錯誤的代碼,可能導致線程無法連接。但是,有一些不好的做法:①你在'async'塊之後錯過了一個分號嗎? ②產卵時不要忙於等待。並且不要取消引用Semaphore對象。相反,你可以在發出信號之前「下」信號量,但是在線程結束時「上升」會好得多。 ③您應該以編程方式聲明所有'@ chrs'都是唯一的,否則您將只加入'$ chr'的最後一個線程。 – amon 2013-05-09 07:43:52

+0

殭屍是在管道中創建的(排序,gzip等)。謝謝你的建議。我學到了很多! – Gahoo 2013-05-09 10:53:58

回答

0

由於您對原始帖子的評論建議 - 您的代碼在這裏沒有任何明顯的錯誤。可能有助於理解的是一個zombie過程。

具體來說 - 這是一個催生的過程(由您的open)已退出,但父母尚未收集它的返回碼。

對於較短的運行代碼,這並不是那麼重要 - 當你的主程序退出時,殭屍將「重新啓動」爲init,這將自動清除它們。

對於長時間運行,您可以使用waitpid進行清理並收集返回代碼。

現在在這個特定的情況下 - 我看不到具體的問題,但我會猜想這與你如何打開你的文件句柄有關。像你這樣打開文件句柄的缺點是,它們在全局範圍內 - 當你做事情時,這只是一個壞消息。

,如果你改變了你的open調用我會想象:

my $pid = open (my $exec_fh, "|-", "executable"); 

,然後在該$pid下你的close那麼你的殭屍會完成所謂的waitpid。測試從waitpid獲得的回報,以瞭解您的哪位高管出錯(如果有),這應該可以幫助您找出原因。

或者 - 設置$SIG{CHLD} = "IGNORE";這意味着你 - 有效地告訴你的子進程'立即消失' - 但是如果它們死了,你將無法從它們那裏得到返回代碼。