似乎在线程中使用管道可能会导致线程变成僵尸。事实上,管道中的命令变成了僵尸,而不是线程。这不会发生很烦人的时间,因为很难找到真正的问题。如何处理这个问题?是什么导致这些?它与管道有关吗?怎么避免这个?
以下是创建示例文件的代码。
#buildTest.pl
use strict;
use warnings;
sub generateChrs{
my ($outfile, $num, $range)=@_;
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)=@line;
my $cur_length=length($reads);
if($last_pos==$pos){
#may dup
if($cur_length>$last_length){
($last_id, $last_pos, $last_reads)=@line;
$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)=@line;
$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 @chrs=@_;
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;
}
¶llelRMdup(&new_chr);
答案 0 :(得分:0)
正如您对原始帖子的评论所暗示的那样 - 您的代码在这里没有任何明显错误。可能有助于理解的是zombie
过程是什么。
具体来说 - 它是一个已经退出的衍生过程(由你的open
),但是父母还没有收集它的返回码。
对于短期运行代码,这并不是那么重要 - 当你的主程序退出时,僵尸会'重新'到init
,这会自动清理它们。
对于长时间运行,您可以使用waitpid
进行清理并收集返回代码。
现在在这种特定情况下 - 我看不到具体的问题,但我会猜测这与你打开文件句柄的方式有关。像你一样打开文件句柄的缺点是它们是全局范围的 - 当你正在做的事情时,这通常是坏消息。
我想如果您将open
来电更改为:
my $pid = open ( my $exec_fh, "|-", "executable" );
然后在你的waitpid
之后$pid
上跟close
打电话,那么你的僵尸就会完成。测试waitpid
的回报,以了解哪些高管有错误(如果有的话),这可以帮助您找出原因。
或者 - 设置$SIG{CHLD} = "IGNORE";
这意味着你 - 有效地 - 告诉你的孩子进程'立即离开' - 但如果他们死了你将无法从他们那里得到返回代码。